summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarshavardhana Ranganath <harsha@gluster.com>2009-07-09 00:50:10 +0000
committerAnand V. Avati <avati@dev.gluster.com>2009-07-09 14:03:38 -0700
commit55f476455c66dc1e21bbbe88a29c9ae304a81002 (patch)
treecdc18eb4b5a950ad541423f482eac3d335c68f02
parentb23c9fcc8a16b8c4a4b1814ff5035a18f03da0f4 (diff)
Fixes for MacOSX and Solaris buildv2.0.4
Fixes for Solaris and MacOSX build errors. Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
-rw-r--r--libglusterfs/src/compat.c133
-rw-r--r--libglusterfs/src/compat.h3
-rw-r--r--libglusterfs/src/protocol.h9
3 files changed, 103 insertions, 42 deletions
diff --git a/libglusterfs/src/compat.c b/libglusterfs/src/compat.c
index bad62b563d5..befc22c039f 100644
--- a/libglusterfs/src/compat.c
+++ b/libglusterfs/src/compat.c
@@ -369,38 +369,6 @@ solaris_getxattr(const char *path,
}
-int
-asprintf(char **string_ptr, const char *format, ...)
-{
- va_list arg;
- char *str;
- int size;
- int rv;
-
- if (!string_ptr || !format)
- return -1;
-
- va_start(arg, format);
- size = vsnprintf(NULL, 0, format, arg);
- size++;
- va_start(arg, format);
- str = MALLOC(size);
- 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);
-}
-
char* strsep(char** str, const char* delims)
{
char* token;
@@ -424,6 +392,107 @@ char* strsep(char** str, const char* delims)
return token;
}
+/* Code comes from libiberty */
+
+int
+vasprintf (char **result, const char *format, va_list args)
+{
+ 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;
+
+ /* this is not really portable but works under Windows */
+ memcpy ( &ap, &args, sizeof (va_list));
+
+ 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;
+ }
+ }
+ }
+ *result = malloc (total_width);
+ if (*result != NULL)
+ return vsprintf (*result, format, args);
+ else
+ return 0;
+}
+
+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;
+}
+
#endif /* GF_SOLARIS_HOST_OS */
#ifndef HAVE_STRNLEN
diff --git a/libglusterfs/src/compat.h b/libglusterfs/src/compat.h
index 228daf5da9d..588ad8b934e 100644
--- a/libglusterfs/src/compat.h
+++ b/libglusterfs/src/compat.h
@@ -218,7 +218,8 @@ enum {
#define lutimes(filename,times) utimes(filename,times)
-int asprintf(char **string_ptr, const char *format, ...);
+int asprintf (char **buf, const char *fmt, ...);
+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);
diff --git a/libglusterfs/src/protocol.h b/libglusterfs/src/protocol.h
index fdbaf85c02c..54734e6399e 100644
--- a/libglusterfs/src/protocol.h
+++ b/libglusterfs/src/protocol.h
@@ -219,13 +219,10 @@ gf_timespec_from_timespec (struct gf_timespec *gf_ts, struct timespec *ts)
#define GF_O_APPEND 02000
#define GF_O_NONBLOCK 04000
#define GF_O_SYNC 010000
-#define GF_O_ASYNC 020000
#define GF_O_DIRECT 040000
#define GF_O_DIRECTORY 0200000
#define GF_O_NOFOLLOW 0400000
-#define GF_O_NOATIME 01000000
-#define GF_O_CLOEXEC 02000000
#define GF_O_LARGEFILE 0100000
@@ -275,13 +272,10 @@ gf_flags_from_flags (uint32_t flags)
XLATE_BIT (flags, gf_flags, O_APPEND);
XLATE_BIT (flags, gf_flags, O_NONBLOCK);
XLATE_BIT (flags, gf_flags, O_SYNC);
- XLATE_BIT (flags, gf_flags, O_ASYNC);
XLATE_BIT (flags, gf_flags, O_DIRECT);
XLATE_BIT (flags, gf_flags, O_DIRECTORY);
XLATE_BIT (flags, gf_flags, O_NOFOLLOW);
- XLATE_BIT (flags, gf_flags, O_NOATIME);
- XLATE_BIT (flags, gf_flags, O_CLOEXEC);
XLATE_BIT (flags, gf_flags, O_LARGEFILE);
@@ -302,13 +296,10 @@ gf_flags_to_flags (uint32_t gf_flags)
UNXLATE_BIT (gf_flags, flags, O_APPEND);
UNXLATE_BIT (gf_flags, flags, O_NONBLOCK);
UNXLATE_BIT (gf_flags, flags, O_SYNC);
- UNXLATE_BIT (gf_flags, flags, O_ASYNC);
UNXLATE_BIT (gf_flags, flags, O_DIRECT);
UNXLATE_BIT (gf_flags, flags, O_DIRECTORY);
UNXLATE_BIT (gf_flags, flags, O_NOFOLLOW);
- UNXLATE_BIT (gf_flags, flags, O_NOATIME);
- UNXLATE_BIT (gf_flags, flags, O_CLOEXEC);
UNXLATE_BIT (gf_flags, flags, O_LARGEFILE);
419' href='#n419'>419 420 421 422 423 424 425 426 427 428 429 430 431 432
/*
   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 "changelog-misc.h"
#include "changelog-mem-types.h"

#include "gf-changelog-helpers.h"
#include "changelog-rpc-common.h"
#include "changelog-lib-messages.h"

#include "syscall.h"

/**
 * Reverse socket: actual data transfer handler. Connection
 * initiator is PROBER, data transfer is REBORP.
 */

struct rpcsvc_program *gf_changelog_reborp_programs[];

void *
gf_changelog_connection_janitor (void *arg)
{
        int32_t ret = 0;
        xlator_t *this = NULL;
        gf_private_t *priv = NULL;
        gf_changelog_t *entry = NULL;
        struct gf_event *event = NULL;
        struct gf_event_list *ev = NULL;
        unsigned long drained = 0;

        this = arg;
        THIS = this;

        priv = this->private;

        while (1) {
                pthread_mutex_lock (&priv->lock);
                {
                        while (list_empty (&priv->cleanups))
                                pthread_cond_wait (&priv->cond, &priv->lock);

                        entry = list_first_entry (&priv->cleanups,
                                                  gf_changelog_t, list);
                        list_del_init (&entry->list);
                }
                pthread_mutex_unlock (&priv->lock);

                drained = 0;
                ev = &entry->event;

                gf_smsg (this->name, GF_LOG_INFO, 0,
                         CHANGELOG_LIB_MSG_CLEANING_BRICK_ENTRY_INFO,
                         "Cleaning brick entry for brick",
                         "brick=%s", entry->brick,
                         NULL);

                /* 0x0: disbale rpc-clnt */
                rpc_clnt_disable (RPC_PROBER (entry));

                /* 0x1: cleanup callback invoker thread */
                ret = gf_cleanup_event (this, ev);
                if (ret)
                        continue;

                /* 0x2: drain pending events */
                while (!list_empty (&ev->events)) {
                        event = list_first_entry (&ev->events,
                                                  struct gf_event, list);
                        gf_smsg (this->name, GF_LOG_INFO, 0,
                                 CHANGELOG_LIB_MSG_DRAINING_EVENT_INFO,
                                 "Draining event",
                                 "seq=%lu", event->seq,
                                 "payload=%d", event->count,
                                 NULL);

                        GF_FREE (event);
                        drained++;
                }

                gf_smsg (this->name, GF_LOG_INFO, 0,
                         CHANGELOG_LIB_MSG_DRAINING_EVENT_INFO,
                         "Drained events",
                         "num=%lu", drained,
                         NULL);

                /* 0x3: freeup brick entry */
                gf_smsg (this->name, GF_LOG_INFO, 0,
                         CHANGELOG_LIB_MSG_FREEING_ENTRY_INFO,
                         "freeing entry",
                         "entry=%p", entry,
                         NULL);
                LOCK_DESTROY (&entry->statelock);
                GF_FREE (entry);
        }

        return NULL;
}

int
gf_changelog_reborp_rpcsvc_notify (rpcsvc_t *rpc, void *mydata,
                                   rpcsvc_event_t event, void *data)
{
        int             ret      = 0;
        xlator_t       *this     = NULL;
        gf_changelog_t *entry    = NULL;

        if (!(event == RPCSVC_EVENT_ACCEPT ||
              event == RPCSVC_EVENT_DISCONNECT))
                return 0;

        entry = mydata;
        this = entry->this;

        switch (event) {
        case RPCSVC_EVENT_ACCEPT:
                ret = sys_unlink (RPC_SOCK(entry));
                if (ret != 0)
                        gf_smsg (this->name, GF_LOG_WARNING, errno,
                                 CHANGELOG_LIB_MSG_UNLINK_FAILED,
                                 "failed to unlink "
                                 "reverse socket",
                                 "path=%s", RPC_SOCK (entry),
                                 NULL);
                if (entry->connected)
                        GF_CHANGELOG_INVOKE_CBK (this, entry->connected,
                                                 entry->brick, entry->ptr);
                break;
        case RPCSVC_EVENT_DISCONNECT:
                if (entry->disconnected)
                        GF_CHANGELOG_INVOKE_CBK (this, entry->disconnected,
                                                 entry->brick, entry->ptr);
                /* passthrough */
        default:
                break;
        }

        return 0;
}

rpcsvc_t *
gf_changelog_reborp_init_rpc_listner (xlator_t *this,
                                      char *path, char *sock, void *cbkdata)
{
        CHANGELOG_MAKE_TMP_SOCKET_PATH (path, sock, UNIX_PATH_MAX);
        return changelog_rpc_server_init (this, sock, cbkdata,
                                          gf_changelog_reborp_rpcsvc_notify,
                                          gf_changelog_reborp_programs);
}

/**
 * This is dirty and painful as of now untill there is event filtering in the
 * server. The entire event buffer is scanned and interested events are picked,
 * whereas we _should_ be notified with the events we were interested in
 * (selected at the time of probe). As of now this is complete BS and needs
 * fixture ASAP. I just made it work, it needs to be better.
 *
 * @FIXME: cleanup this bugger once server filters events.
 */
void
gf_changelog_invoke_callback (gf_changelog_t *entry,
                              struct iovec **vec, int payloadcnt)
{
        int i = 0;
        int evsize = 0;
        xlator_t *this = NULL;
        changelog_event_t *event = NULL;

        this = entry->this;

        for (; i < payloadcnt; i++) {
                event = (changelog_event_t *)vec[i]->iov_base;
                evsize = vec[i]->iov_len / CHANGELOG_EV_SIZE;

                for (; evsize > 0; evsize--, event++) {
                        if (gf_changelog_filter_check (entry, event)) {
                                GF_CHANGELOG_INVOKE_CBK (this,
                                                         entry->callback,
                                                         entry->brick,
                                                         entry->ptr, event);
                        }
                }
        }
}

/**
 * Ordered event handler is self-adaptive.. if the event sequence number
 * is what's expected (->next_seq) there is no ordering list that's
 * maintained. On out-of-order event notifications, event buffers are
 * dynamically allocated and ordered.
 */

int
__is_expected_sequence (struct gf_event_list *ev, struct gf_event *event)
{
        return (ev->next_seq == event->seq);
}

int
__can_process_event (struct gf_event_list *ev, struct gf_event **event)
{
        *event = list_first_entry (&ev->events, struct gf_event, list);

        if (__is_expected_sequence (ev, *event)) {
                list_del (&(*event)->list);
                ev->next_seq++;
                return 1;
        }

        return 0;
}

void
pick_event_ordered (struct gf_event_list *ev, struct gf_event **event)
{
        pthread_mutex_lock (&ev->lock);
        {
                while (list_empty (&ev->events)
                       || !__can_process_event (ev, event))
                        pthread_cond_wait (&ev->cond, &ev->lock);
        }
        pthread_mutex_unlock (&ev->lock);
}

void
pick_event_unordered (struct gf_event_list *ev, struct gf_event **event)
{
        pthread_mutex_lock (&ev->lock);
        {
                while (list_empty (&ev->events))
                        pthread_cond_wait (&ev->cond, &ev->lock);
                *event = list_first_entry (&ev->events, struct gf_event, list);
                list_del (&(*event)->list);
        }
        pthread_mutex_unlock (&ev->lock);
}

void *
gf_changelog_callback_invoker (void *arg)
{
        xlator_t             *this   = NULL;
        gf_changelog_t       *entry  = NULL;
        struct iovec         *vec    = NULL;
        struct gf_event      *event  = NULL;
        struct gf_event_list *ev     = NULL;

        ev    = arg;
        entry = ev->entry;
        THIS = this = entry->this;

        while (1) {
                entry->pickevent (ev, &event);

                vec = (struct iovec *) &event->iov;
                gf_changelog_invoke_callback (entry, &vec, event->count);

                GF_FREE (event);
        }

        return NULL;
}

static int
orderfn (struct list_head *pos1, struct list_head *pos2)
{
        struct gf_event *event1 = NULL;
        struct gf_event *event2 = NULL;

        event1 = list_entry (pos1, struct gf_event, list);
        event2 = list_entry (pos2, struct gf_event, list);

        if  (event1->seq > event2->seq)
                return 1;
        return -1;
}

void
queue_ordered_event (struct gf_event_list *ev, struct gf_event *event)
{
        /* add event to the ordered event list and wake up listner(s) */
        pthread_mutex_lock (&ev->lock);
        {
                list_add_order (&event->list, &ev->events, orderfn);
                if (!ev->next_seq)
                        ev->next_seq = event->seq;
                if (ev->next_seq == event->seq)
                        pthread_cond_signal (&ev->cond);
        }
        pthread_mutex_unlock (&ev->lock);
}

void
queue_unordered_event (struct gf_event_list *ev, struct gf_event *event)
{
        /* add event to the tail of the queue and wake up listener(s) */
        pthread_mutex_lock (&ev->lock);
        {
                list_add_tail (&event->list, &ev->events);
                pthread_cond_signal (&ev->cond);
        }
        pthread_mutex_unlock (&ev->lock);
}

int
gf_changelog_event_handler (rpcsvc_request_t *req,
                            xlator_t *this, gf_changelog_t *entry)
{
        int                   i          = 0;
        size_t                payloadlen = 0;
        ssize_t               len        = 0;
        int                   payloadcnt = 0;
        changelog_event_req   rpc_req    = {0,};
        changelog_event_rsp   rpc_rsp    = {0,};
        struct iovec         *vec        = NULL;
        struct gf_event      *event      = NULL;
        struct gf_event_list *ev         = NULL;

        ev = &entry->event;

        len = xdr_to_generic (req->msg[0],
                              &rpc_req, (xdrproc_t)xdr_changelog_event_req);
        if (len < 0) {
                gf_msg (this->name, GF_LOG_ERROR, 0,
                        CHANGELOG_LIB_MSG_XDR_DECODING_FAILED,
                        "xdr decoding failed");
                req->rpc_err = GARBAGE_ARGS;
                goto handle_xdr_error;
        }

        if (len < req->msg[0].iov_len) {
                payloadcnt = 1;
                payloadlen = (req->msg[0].iov_len - len);
        }
        for (i = 1; i < req->count; i++) {
                payloadcnt++;
                payloadlen += req->msg[i].iov_len;
        }

        event = GF_CALLOC (1, GF_EVENT_CALLOC_SIZE (payloadcnt, payloadlen),
                           gf_changelog_mt_libgfchangelog_event_t);
        if (!event)
                goto handle_xdr_error;
        INIT_LIST_HEAD (&event->list);

        payloadlen   = 0;
        event->seq   = rpc_req.seq;
        event->count = payloadcnt;

        /* deep copy IO vectors */
        vec = &event->iov[0];
        GF_EVENT_ASSIGN_IOVEC (vec, event,
                               (req->msg[0].iov_len - len), payloadlen);
        (void) memcpy (vec->iov_base,
                       req->msg[0].iov_base + len, vec->iov_len);

        for (i = 1; i < req->count; i++) {
                vec = &event->iov[i];
                GF_EVENT_ASSIGN_IOVEC (vec, event,
                                       req->msg[i].iov_len, payloadlen);
                (void) memcpy (event->iov[i].iov_base,
                               req->msg[i].iov_base, req->msg[i].iov_len);
        }

        gf_msg_debug (this->name, 0,
                      "seq: %lu [%s] (time: %lu.%lu), (vec: %d, len: %zd)",
                      rpc_req.seq, entry->brick, rpc_req.tv_sec,
                      rpc_req.tv_usec, payloadcnt, payloadlen);

        /* dispatch event */
        entry->queueevent (ev, event);

        /* ack sequence number */
        rpc_rsp.op_ret = 0;
        rpc_rsp.seq    = rpc_req.seq;

        goto submit_rpc;

 handle_xdr_error:
        rpc_rsp.op_ret = -1;
        rpc_rsp.seq    = 0;     /* invalid */
 submit_rpc:
        return changelog_rpc_sumbit_reply (req, &rpc_rsp, NULL, 0, NULL,
                                           (xdrproc_t)xdr_changelog_event_rsp);
}

int
gf_changelog_reborp_handle_event (rpcsvc_request_t *req)
{
        xlator_t       *this  = NULL;
        rpcsvc_t       *svc   = NULL;
        gf_changelog_t *entry = NULL;

        svc = rpcsvc_request_service (req);
        entry = svc->mydata;

        this = THIS = entry->this;

        return gf_changelog_event_handler (req, this, entry);
}

rpcsvc_actor_t gf_changelog_reborp_actors[CHANGELOG_REV_PROC_MAX] = {
        [CHANGELOG_REV_PROC_EVENT] = {
                "CHANGELOG EVENT HANDLER", CHANGELOG_REV_PROC_EVENT,
                gf_changelog_reborp_handle_event, NULL, 0, DRC_NA
        },
};

/**
 * Do not use synctask as the RPC layer dereferences ->mydata as THIS.
 * In gf_changelog_setup_rpc(), @cbkdata is of type @gf_changelog_t,
 * and that's required to invoke the callback with the appropriate
 * brick path and it's private data.
 */
struct rpcsvc_program gf_changelog_reborp_prog = {
        .progname  = "LIBGFCHANGELOG REBORP",
        .prognum   = CHANGELOG_REV_RPC_PROCNUM,
        .progver   = CHANGELOG_REV_RPC_PROCVER,
        .numactors = CHANGELOG_REV_PROC_MAX,
        .actors    = gf_changelog_reborp_actors,
        .synctask  = _gf_false,
};

struct rpcsvc_program *gf_changelog_reborp_programs[] = {
        &gf_changelog_reborp_prog,
        NULL,
};