diff options
Diffstat (limited to 'xlators/features')
| -rw-r--r-- | xlators/features/Makefile.am | 2 | ||||
| -rw-r--r-- | xlators/features/barrier/Makefile.am | 3 | ||||
| -rw-r--r-- | xlators/features/barrier/src/Makefile.am | 16 | ||||
| -rw-r--r-- | xlators/features/barrier/src/barrier-mem-types.h | 20 | ||||
| -rw-r--r-- | xlators/features/barrier/src/barrier.c | 520 | ||||
| -rw-r--r-- | xlators/features/barrier/src/barrier.h | 91 | 
6 files changed, 651 insertions, 1 deletions
diff --git a/xlators/features/Makefile.am b/xlators/features/Makefile.am index d2f5ef19290..1fdd474c20a 100644 --- a/xlators/features/Makefile.am +++ b/xlators/features/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = locks quota read-only mac-compat quiesce marker index \ +SUBDIRS = locks quota read-only mac-compat quiesce marker index barrier \  	  protect compress changelog gfid-access $(GLUPY_SUBDIR) qemu-block # trash path-converter # filter  CLEANFILES = diff --git a/xlators/features/barrier/Makefile.am b/xlators/features/barrier/Makefile.am new file mode 100644 index 00000000000..a985f42a877 --- /dev/null +++ b/xlators/features/barrier/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES = diff --git a/xlators/features/barrier/src/Makefile.am b/xlators/features/barrier/src/Makefile.am new file mode 100644 index 00000000000..8859be328d3 --- /dev/null +++ b/xlators/features/barrier/src/Makefile.am @@ -0,0 +1,16 @@ +xlator_LTLIBRARIES = barrier.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features + +barrier_la_LDFLAGS = -module -avoid-version + +barrier_la_SOURCES = barrier.c + +barrier_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +noinst_HEADERS = barrier.h barrier-mem-types.h + +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src + +AM_CFLAGS = -Wall $(GF_CFLAGS) + +CLEANFILES = diff --git a/xlators/features/barrier/src/barrier-mem-types.h b/xlators/features/barrier/src/barrier-mem-types.h new file mode 100644 index 00000000000..36647a66966 --- /dev/null +++ b/xlators/features/barrier/src/barrier-mem-types.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 __BARRIER_MEM_TYPES_H__ +#define __BARRIER_MEM_TYPES_H__ + +#include "mem-types.h" + +enum gf_barrier_mem_types_ { +        gf_barrier_mt_priv_t = gf_common_mt_end + 1, +        gf_barrier_mt_end +}; +#endif diff --git a/xlators/features/barrier/src/barrier.c b/xlators/features/barrier/src/barrier.c new file mode 100644 index 00000000000..566c67f305f --- /dev/null +++ b/xlators/features/barrier/src/barrier.c @@ -0,0 +1,520 @@ +/* +   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 _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "barrier.h" +#include "defaults.h" +#include "call-stub.h" + +int32_t +barrier_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) +{ +        BARRIER_FOP_CBK (writev, out, frame, this, op_ret, op_errno, +                         prebuf, postbuf, xdata); +out: +        return 0; +} + +int32_t +barrier_fremovexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                          int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ +        BARRIER_FOP_CBK (fremovexattr, out, frame, this, op_ret, op_errno, +                         xdata); +out: +        return 0; +} + +int32_t +barrier_removexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                         int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ +        BARRIER_FOP_CBK (removexattr, out, frame, this, op_ret, op_errno, +                         xdata); +out: +        return 0; +} + +int32_t +barrier_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) +{ +        BARRIER_FOP_CBK (truncate, out, frame, this, op_ret, op_errno, prebuf, +                         postbuf, xdata); +out: +        return 0; +} + +int32_t +barrier_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) +{ +        BARRIER_FOP_CBK (ftruncate, out, frame, this, op_ret, op_errno, prebuf, +                         postbuf, xdata); +out: +        return 0; +} + +int32_t +barrier_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) +{ +        BARRIER_FOP_CBK (rename, out, frame, this, op_ret, op_errno, buf, +                         preoldparent, postoldparent, prenewparent, +                         postnewparent, xdata); +out: +        return 0; +} + +int32_t +barrier_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) +{ +        BARRIER_FOP_CBK (rmdir, out, frame, this, op_ret, op_errno, preparent, +                         postparent, xdata); +out: +        return 0; +} + +int32_t +barrier_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) +{ +        BARRIER_FOP_CBK (unlink, out, frame, this, op_ret, op_errno, preparent, +                         postparent, xdata); +out: +        return 0; +} + +int32_t +barrier_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) +{ +        BARRIER_FOP_CBK (fsync, out, frame, this, op_ret, op_errno, +                         prebuf, postbuf, xdata); +out: +        return 0; +} + +int32_t +barrier_writev (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) +{ +        if (!(flags & O_SYNC)) { +                STACK_WIND_TAIL (frame, FIRST_CHILD(this), +                                 FIRST_CHILD(this)->fops->writev, +                                 fd, vector, count, off, flags, iobref, xdata); + +                return 0; +        } + +        STACK_WIND (frame, barrier_writev_cbk, FIRST_CHILD(this), +                    FIRST_CHILD(this)->fops->writev, fd, vector, count, +                    off, flags, iobref, xdata); +        return 0; +} + +int32_t +barrier_fremovexattr (call_frame_t *frame, xlator_t *this, fd_t *fd, +                      const char *name, dict_t *xdata) +{ +        STACK_WIND (frame, barrier_fremovexattr_cbk, FIRST_CHILD (this), +                    FIRST_CHILD (this)->fops->fremovexattr, +                    fd, name, xdata); +        return 0; +} + +int32_t +barrier_removexattr (call_frame_t *frame, xlator_t *this, loc_t *loc, +                     const char *name, dict_t *xdata) +{ +        STACK_WIND (frame, barrier_removexattr_cbk, FIRST_CHILD (this), +                    FIRST_CHILD (this)->fops->removexattr, +                    loc, name, xdata); +        return 0; +} + +int32_t +barrier_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, +                  off_t offset, dict_t *xdata) +{ +        STACK_WIND (frame, barrier_truncate_cbk, FIRST_CHILD (this), +                    FIRST_CHILD (this)->fops->truncate, +                    loc, offset, xdata); +        return 0; +} + +int32_t +barrier_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, +                loc_t *newloc, dict_t *xdata) +{ +        STACK_WIND (frame, barrier_rename_cbk, FIRST_CHILD (this), +                    FIRST_CHILD (this)->fops->rename, +                    oldloc, newloc, xdata); +        return 0; +} + +int +barrier_rmdir (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, +               dict_t *xdata) +{ +        STACK_WIND (frame, barrier_rmdir_cbk, FIRST_CHILD (this), +                    FIRST_CHILD (this)->fops->rmdir, +                    loc, flags, xdata); +        return 0; +} + +int32_t +barrier_unlink (call_frame_t *frame, xlator_t *this, +                loc_t *loc, int xflag, dict_t *xdata) +{ +        STACK_WIND (frame, barrier_unlink_cbk, FIRST_CHILD (this), +                    FIRST_CHILD (this)->fops->unlink, +                    loc, xflag, xdata); +        return 0; +} + +int32_t +barrier_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, +                   off_t offset, dict_t *xdata) +{ +        STACK_WIND (frame, barrier_ftruncate_cbk, FIRST_CHILD (this), +                    FIRST_CHILD (this)->fops->ftruncate, +                    fd, offset, xdata); +        return 0; +} + +int32_t +barrier_fsync (call_frame_t *frame, xlator_t *this, fd_t *fd, +               int32_t flags, dict_t *xdata) +{ +        STACK_WIND (frame, barrier_fsync_cbk, FIRST_CHILD (this), +                    FIRST_CHILD (this)->fops->fsync, +                    fd, flags, xdata); +        return 0; +} + +call_stub_t * +__barrier_dequeue (xlator_t *this, struct list_head *queue) +{ +        call_stub_t    *stub            = NULL; +        barrier_priv_t *priv            = NULL; + +        priv = this->private; +        GF_ASSERT (priv); + +        if (list_empty (queue)) +                goto out; + +        stub = list_entry (queue->next, call_stub_t, list); +        list_del_init (&stub->list); + +out: +        return stub; +} + +void +barrier_dequeue_all (xlator_t *this, struct list_head *queue) +{ +        call_stub_t            *stub    = NULL; + +        gf_log (this->name, GF_LOG_INFO, "Dequeuing all the barriered fops"); + +        /* TODO: Start the below task in a new thread */ +        while ((stub = __barrier_dequeue (this, queue))) +                call_resume (stub); + +        gf_log (this->name, GF_LOG_INFO, "Dequeuing the barriered fops is " +                                         "finished"); +        return; +} + +void +barrier_timeout (void *data) +{ +        xlator_t               *this    = NULL; +        barrier_priv_t         *priv    = NULL; +        struct list_head        queue   = {0,}; + +        this = data; +        THIS = this; +        priv = this->private; + +        INIT_LIST_HEAD (&queue); + +        gf_log (this->name, GF_LOG_CRITICAL, "Disabling barrier because of " +                                             "the barrier timeout."); + +        LOCK (&priv->lock); +        { +                __barrier_disable (this, &queue); +        } +        UNLOCK (&priv->lock); + +        barrier_dequeue_all (this, &queue); + +        return; +} + +void +__barrier_enqueue (xlator_t *this, call_stub_t *stub) +{ +        barrier_priv_t *priv    = NULL; + +        priv = this->private; +        GF_ASSERT (priv); + +        list_add_tail (&stub->list, &priv->queue); +        priv->queue_size++; + +        return; +} + +void +__barrier_disable (xlator_t *this, struct list_head *queue) +{ +        GF_UNUSED int   ret     = 0; +        barrier_priv_t *priv    = NULL; + +        priv = this->private; +        GF_ASSERT (priv); + +        if (priv->timer) { +                ret = gf_timer_call_cancel (this->ctx, priv->timer); +                priv->timer = NULL; +        } + +        list_splice_init (&priv->queue, queue); +        priv->queue_size = 0; +        priv->barrier_enabled = _gf_false; +} + +int +__barrier_enable (xlator_t *this, barrier_priv_t *priv) +{ +        int             ret     = -1; + +        priv->timer = gf_timer_call_after (this->ctx, priv->timeout, +                                           barrier_timeout, (void *) this); +        if (!priv->timer) { +                gf_log (this->name, GF_LOG_CRITICAL, "Couldn't add barrier " +                                                     "timeout event."); +                goto out; +        } + +        priv->barrier_enabled = _gf_true; +        ret = 0; +out: +        return ret; +} + +int +reconfigure (xlator_t *this, dict_t *options) +{ +        barrier_priv_t  *priv                   = NULL; +        gf_boolean_t     past                   = _gf_false; +        int              ret                    = -1; +        gf_boolean_t     barrier_enabled        = _gf_false; +        uint32_t         timeout                = {0,}; +        struct list_head queue                  = {0,}; + +        priv = this->private; +        GF_ASSERT (priv); + +        GF_OPTION_RECONF ("barrier", barrier_enabled, options, bool, out); +        GF_OPTION_RECONF ("timeout", timeout, options, time, out); + +        INIT_LIST_HEAD (&queue); + +        LOCK (&priv->lock); +        { +                past = priv->barrier_enabled; + +                switch (past) { +                case _gf_false: +                        if (barrier_enabled) { +                                ret = __barrier_enable (this, priv); +                                if (ret) +                                        goto unlock; + +                        } else { +                                gf_log (this->name, GF_LOG_ERROR, +                                        "Already disabled"); +                                goto unlock; +                        } +                        break; + +                case _gf_true: +                        if (!barrier_enabled) { +                                __barrier_disable (this, &queue); + +                        } else { +                                gf_log (this->name, GF_LOG_ERROR, +                                        "Already enabled"); +                                goto unlock; +                        } +                        break; +                } + +                priv->timeout.tv_sec = timeout; + +                ret = 0; +        } +unlock: +        UNLOCK (&priv->lock); + +        if (!list_empty (&queue)) +                barrier_dequeue_all (this, &queue); + +out: +        return ret; +} + +int32_t +mem_acct_init (xlator_t *this) +{ +        int     ret = -1; + +        ret = xlator_mem_acct_init (this, gf_barrier_mt_end + 1); +        if (ret) +                gf_log (this->name, GF_LOG_ERROR, "Memory accounting " +                        "initialization failed."); + +        return ret; +} + +int +init (xlator_t *this) +{ +        int                     ret     = -1; +        barrier_priv_t         *priv    = NULL; +        uint32_t                timeout = {0,}; + +        if (!this->children || this->children->next) { +                gf_log (this->name, GF_LOG_ERROR, +                        "'barrier' not configured with exactly one child"); +                goto out; +        } + +        if (!this->parents) +                gf_log (this->name, GF_LOG_WARNING, +                        "dangling volume. check volfile "); + +        priv = GF_CALLOC (1, sizeof (*priv), gf_barrier_mt_priv_t); +        if (!priv) +                goto out; + +        LOCK_INIT (&priv->lock); + +        GF_OPTION_INIT ("barrier", priv->barrier_enabled, bool, out); +        GF_OPTION_INIT ("timeout", timeout, time, out); +        priv->timeout.tv_sec = timeout; + +        INIT_LIST_HEAD (&priv->queue); + +        if (priv->barrier_enabled) { +                ret = __barrier_enable (this, priv); +                if (ret == -1) +                        goto out; +        } + +        this->private = priv; +        ret = 0; +out: +        return ret; +} + +void +fini (xlator_t *this) +{ +        barrier_priv_t         *priv    = NULL; +        struct list_head        queue   = {0,}; + +        priv = this->private; +        if (!priv) +                goto out; + +        INIT_LIST_HEAD (&queue); + +        gf_log (this->name, GF_LOG_INFO, "Disabling barriering and dequeuing " +                                         "all the queued fops"); +        LOCK (&priv->lock); +        { +                __barrier_disable (this, &queue); +        } +        UNLOCK (&priv->lock); + +        if (!list_empty (&queue)) +                barrier_dequeue_all (this, &queue); + +        this->private = NULL; + +        LOCK_DESTROY (&priv->lock); +        GF_FREE (priv); +out: +        return; +} + +struct xlator_fops fops = { + +        /* Barrier Class fops */ +        .rmdir          = barrier_rmdir, +        .unlink         = barrier_unlink, +        .rename         = barrier_rename, +        .removexattr    = barrier_removexattr, +        .fremovexattr   = barrier_fremovexattr, +        .truncate       = barrier_truncate, +        .ftruncate      = barrier_ftruncate, +        .fsync          = barrier_fsync, + +        /* Writes with only O_SYNC flag */ +        .writev         = barrier_writev, +}; + +struct xlator_dumpops dumpops; + +struct xlator_cbks cbks; + +struct volume_options options[] = { +        { .key  = {"barrier"}, +          .type = GF_OPTION_TYPE_BOOL, +          .default_value = "off", +          .description = "When \"on\", blocks acknowledgements to application " +                         "for file operations such as rmdir, rename, unlink, " +                         "removexattr, fremovexattr, truncate, ftruncate, " +                         "write (with O_SYNC), fsync. It is turned \"off\" by " +                         "default." +        }, +        { .key = {"timeout"}, +          .type = GF_OPTION_TYPE_TIME, +          .default_value = "120", +          .description = "After 'timeout' seconds since the time 'barrier' " +                         "option was set to \"on\", acknowledgements to file " +                         "operations are no longer blocked and previously " +                         "blocked acknowledgements are sent to the application" +        }, +        { .key  = {NULL} }, +}; diff --git a/xlators/features/barrier/src/barrier.h b/xlators/features/barrier/src/barrier.h new file mode 100644 index 00000000000..8face9f6512 --- /dev/null +++ b/xlators/features/barrier/src/barrier.h @@ -0,0 +1,91 @@ +/* +   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 __BARRIER_H__ +#define __BARRIER_H__ + +#include "barrier-mem-types.h" +#include "xlator.h" +#include "timer.h" +#include "call-stub.h" + +#define BARRIER_SAFE_ASSIGN(lock, to, value)                    \ +        do {                                                    \ +                LOCK (&(lock));                                 \ +                {                                               \ +                        to = value;                             \ +                }                                               \ +                UNLOCK (&(lock));                               \ +        } while (0) + +#define BARRIER_FOP_CBK(fop_name, label, frame, this, params ...)       \ +        do {                                                            \ +                barrier_priv_t         *_priv           = NULL;         \ +                call_stub_t            *_stub           = NULL;         \ +                gf_boolean_t            _barrier_enabled= _gf_false;    \ +                struct list_head        queue           = {0, };        \ +                                                                        \ +                INIT_LIST_HEAD (&queue);                                \ +                                                                        \ +                _priv = this->private;                                  \ +                GF_ASSERT (_priv);                                      \ +                                                                        \ +                LOCK (&_priv->lock);                                    \ +                {                                                       \ +                        if (_priv->barrier_enabled) {                   \ +                                _barrier_enabled = _priv->barrier_enabled;\ +                                                                        \ +                                _stub = fop_##fop_name##_cbk_stub       \ +                                        (frame,                         \ +                                         default_##fop_name##_cbk_resume,\ +                                         params);                       \ +                                if (!_stub) {                           \ +                                        __barrier_disable (this, &queue);\ +                                        goto unlock;                    \ +                                }                                       \ +                                                                        \ +                                __barrier_enqueue (this, _stub);        \ +                        }                                               \ +                }                                                       \ +unlock:                                                                 \ +                UNLOCK (&_priv->lock);                                  \ +                                                                        \ +                if (_stub)                                              \ +                        goto label;                                     \ +                                                                        \ +                if (_barrier_enabled && !_stub) {                       \ +                        gf_log (this->name, GF_LOG_CRITICAL,            \ +                                "Failed to barrier FOPs, disabling "    \ +                                "barrier. FOP: %s, ERROR: %s",          \ +                                #fop_name, strerror (ENOMEM));          \ +                        barrier_dequeue_all (this, &queue);             \ +                }                                                       \ +                                                                        \ +                STACK_UNWIND_STRICT (fop_name, frame, params);          \ +                goto label;                                             \ +        } while (0) + +typedef struct { +        gf_timer_t       *timer; +        gf_boolean_t      barrier_enabled; +        gf_lock_t         lock; +        struct list_head  queue; +        struct timespec   timeout; +        uint32_t          queue_size; +} barrier_priv_t; + +int __barrier_enable (xlator_t *this, barrier_priv_t *priv); +void __barrier_enqueue (xlator_t *this, call_stub_t *stub); +void __barrier_disable (xlator_t *this, struct list_head *queue); +void barrier_timeout (void *data); +void barrier_dequeue_all (xlator_t *this, struct list_head *queue); +call_stub_t *__barrier_dequeue (xlator_t *this, struct list_head *queue); + +#endif  | 
