diff options
26 files changed, 1373 insertions, 205 deletions
diff --git a/glusterfsd/src/glusterfsd-mgmt.c b/glusterfsd/src/glusterfsd-mgmt.c index d2a95a64bb3..f91cdc46ebe 100644 --- a/glusterfsd/src/glusterfsd-mgmt.c +++ b/glusterfsd/src/glusterfsd-mgmt.c @@ -1248,16 +1248,16 @@ rpc_clnt_prog_t clnt_handshake_prog = {  };  rpcsvc_actor_t glusterfs_actors[] = { -        [GLUSTERD_BRICK_NULL]          = {"NULL", GLUSTERD_BRICK_NULL, glusterfs_handle_rpc_msg, NULL, 0}, -        [GLUSTERD_BRICK_TERMINATE]     = {"TERMINATE", GLUSTERD_BRICK_TERMINATE, glusterfs_handle_terminate, NULL, 0}, -        [GLUSTERD_BRICK_XLATOR_INFO]   = {"TRANSLATOR INFO", GLUSTERD_BRICK_XLATOR_INFO, glusterfs_handle_translator_info_get, NULL, 0}, -        [GLUSTERD_BRICK_XLATOR_OP]     = {"TRANSLATOR OP", GLUSTERD_BRICK_XLATOR_OP, glusterfs_handle_translator_op, NULL, 0}, -        [GLUSTERD_BRICK_STATUS]        = {"STATUS", GLUSTERD_BRICK_STATUS, glusterfs_handle_brick_status, NULL, 0}, -        [GLUSTERD_BRICK_XLATOR_DEFRAG] = {"TRANSLATOR DEFRAG", GLUSTERD_BRICK_XLATOR_DEFRAG, glusterfs_handle_defrag, NULL, 0}, -        [GLUSTERD_NODE_PROFILE]        = {"NFS PROFILE", GLUSTERD_NODE_PROFILE, glusterfs_handle_nfs_profile, NULL, 0}, -        [GLUSTERD_NODE_STATUS]         = {"NFS STATUS", GLUSTERD_NODE_STATUS, glusterfs_handle_node_status, NULL, 0}, +        [GLUSTERD_BRICK_NULL]          = {"NULL",              GLUSTERD_BRICK_NULL,          glusterfs_handle_rpc_msg,             NULL, 0, DRC_NA}, +        [GLUSTERD_BRICK_TERMINATE]     = {"TERMINATE",         GLUSTERD_BRICK_TERMINATE,     glusterfs_handle_terminate,           NULL, 0, DRC_NA}, +        [GLUSTERD_BRICK_XLATOR_INFO]   = {"TRANSLATOR INFO",   GLUSTERD_BRICK_XLATOR_INFO,   glusterfs_handle_translator_info_get, NULL, 0, DRC_NA}, +        [GLUSTERD_BRICK_XLATOR_OP]     = {"TRANSLATOR OP",     GLUSTERD_BRICK_XLATOR_OP,     glusterfs_handle_translator_op,       NULL, 0, DRC_NA}, +        [GLUSTERD_BRICK_STATUS]        = {"STATUS",            GLUSTERD_BRICK_STATUS,        glusterfs_handle_brick_status,        NULL, 0, DRC_NA}, +        [GLUSTERD_BRICK_XLATOR_DEFRAG] = {"TRANSLATOR DEFRAG", GLUSTERD_BRICK_XLATOR_DEFRAG, glusterfs_handle_defrag,              NULL, 0, DRC_NA}, +        [GLUSTERD_NODE_PROFILE]        = {"NFS PROFILE",       GLUSTERD_NODE_PROFILE,        glusterfs_handle_nfs_profile,         NULL, 0, DRC_NA}, +        [GLUSTERD_NODE_STATUS]         = {"NFS STATUS",        GLUSTERD_NODE_STATUS,         glusterfs_handle_node_status,         NULL, 0, DRC_NA},  #ifdef HAVE_BD_XLATOR -        [GLUSTERD_BRICK_BD_OP]         = {"BD OP", GLUSTERD_BRICK_BD_OP, glusterfs_handle_bd_op, NULL, 0} +        [GLUSTERD_BRICK_BD_OP]         = {"BD OP",             GLUSTERD_BRICK_BD_OP,         glusterfs_handle_bd_op,               NULL, 0, DRC_NA}  #endif  }; diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index 9375c5d407a..b44c1d0b370 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -1939,6 +1939,50 @@ out:          return ret;  } +/** + * gf_sock_union_equal_addr - check if two given gf_sock_unions have same addr + * + * @param a - first sock union + * @param b - second sock union + * @return _gf_true if a and b have same ipv{4,6} addr, _gf_false otherwise + */ +gf_boolean_t +gf_sock_union_equal_addr (union gf_sock_union *a, +                          union gf_sock_union *b) +{ +        if (!a || !b) { +                gf_log ("common-utils", GF_LOG_ERROR, "Invalid arguments" +                        " to gf_sock_union_equal_addr"); +                return _gf_false; +        } + +        if (a->storage.ss_family != b->storage.ss_family) +                return _gf_false; + +        switch (a->storage.ss_family) { +        case AF_INET: +                if (a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr) +                        return _gf_true; +                else +                        return _gf_false; + +        case AF_INET6: +                if (memcmp ((void *)(&a->sin6.sin6_addr), +                            (void *)(&b->sin6.sin6_addr), +                            sizeof (a->sin6.sin6_addr))) +                        return _gf_false; +                else +                        return _gf_true; + +        default: +                gf_log ("common-utils", GF_LOG_DEBUG, +                        "Unsupported/invalid address family"); +                break; +        } + +        return _gf_false; +} +  /*Thread safe conversion function*/  char *  uuid_utoa (uuid_t uuid) diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h index e1193031c9d..1fb36d658f7 100644 --- a/libglusterfs/src/common-utils.h +++ b/libglusterfs/src/common-utils.h @@ -557,6 +557,8 @@ char valid_internet_address (char *address, gf_boolean_t wildcard_acc);  char valid_ipv4_wildcard_check (char *address);  char valid_ipv6_wildcard_check (char *address);  char valid_wildcard_internet_address (char *address); +gf_boolean_t gf_sock_union_equal_addr (union gf_sock_union *a, +                                       union gf_sock_union *b);  char *uuid_utoa (uuid_t uuid);  char *uuid_utoa_r (uuid_t uuid, char *dst); diff --git a/libglusterfs/src/list.h b/libglusterfs/src/list.h index 35fccdf25a5..7f3712b51b4 100644 --- a/libglusterfs/src/list.h +++ b/libglusterfs/src/list.h @@ -175,4 +175,16 @@ list_append_init (struct list_head *list, struct list_head *head)  	     &pos->member != (head); 					\  	     pos = n, n = list_entry(n->member.next, typeof(*n), member)) +#define list_for_each_entry_reverse(pos, head, member)                  \ +	for (pos = list_entry((head)->prev, typeof(*pos), member);      \ +	     &pos->member != (head);                                    \ +	     pos = list_entry(pos->member.prev, typeof(*pos), member)) + + +#define list_for_each_entry_safe_reverse(pos, n, head, member)          \ +	for (pos = list_entry((head)->prev, typeof(*pos), member),      \ +	        n = list_entry(pos->member.prev, typeof(*pos), member); \ +	     &pos->member != (head);                                    \ +	     pos = n, n = list_entry(n->member.prev, typeof(*n), member)) +  #endif /* _LLIST_H */ diff --git a/libglusterfs/src/mem-types.h b/libglusterfs/src/mem-types.h index 015cd1a3b0e..4c78f46071e 100644 --- a/libglusterfs/src/mem-types.h +++ b/libglusterfs/src/mem-types.h @@ -104,6 +104,10 @@ enum gf_common_mem_types_ {          gf_common_mt_eh_t                 = 88,          gf_common_mt_store_handle_t       = 89,          gf_common_mt_store_iter_t         = 90, -        gf_common_mt_end                  = 91 +        gf_common_mt_drc_client_t         = 91, +        gf_common_mt_drc_globals_t        = 92, +        gf_common_mt_drc_rbtree_node_t    = 93, +        gf_common_mt_iov_base_t           = 94, +        gf_common_mt_end                  = 95,  };  #endif diff --git a/rpc/rpc-lib/src/Makefile.am b/rpc/rpc-lib/src/Makefile.am index ca62a27f964..f19c3c8a431 100644 --- a/rpc/rpc-lib/src/Makefile.am +++ b/rpc/rpc-lib/src/Makefile.am @@ -1,16 +1,18 @@  lib_LTLIBRARIES = libgfrpc.la  libgfrpc_la_SOURCES = auth-unix.c rpcsvc-auth.c rpcsvc.c auth-null.c \ -	rpc-transport.c xdr-rpc.c xdr-rpcclnt.c rpc-clnt.c auth-glusterfs.c +	rpc-transport.c xdr-rpc.c xdr-rpcclnt.c rpc-clnt.c auth-glusterfs.c \ +	rpc-drc.c  libgfrpc_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la  noinst_HEADERS = rpcsvc.h rpc-transport.h xdr-common.h xdr-rpc.h xdr-rpcclnt.h \ -	rpc-clnt.h rpcsvc-common.h protocol-common.h +	rpc-clnt.h rpcsvc-common.h protocol-common.h rpc-drc.h  AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \  	-I$(top_srcdir)/rpc/xdr/src \ -	-DRPC_TRANSPORTDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/rpc-transport\" +	-DRPC_TRANSPORTDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/rpc-transport\" \ +	-I$(top_srcdir)/contrib/rbtree  AM_CFLAGS = -Wall $(GF_CFLAGS) diff --git a/rpc/rpc-lib/src/rpc-drc.c b/rpc/rpc-lib/src/rpc-drc.c new file mode 100644 index 00000000000..66d07cfe6bd --- /dev/null +++ b/rpc/rpc-lib/src/rpc-drc.c @@ -0,0 +1,811 @@ +/* +  Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> +  This file is part of GlusterFS. + +  This file is licensed to you under your choice of the GNU Lesser +  General Public License, version 3 or any later version (LGPLv3 or +  later), or the GNU General Public License, version 2 (GPLv2), in all +  cases as published by the Free Software Foundation. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "rpcsvc.h" +#ifndef RPC_DRC_H +#include "rpc-drc.h" +#endif +#include "locking.h" +#include "hashfn.h" +#include "common-utils.h" +#include "statedump.h" +#include "mem-pool.h" + +#include <netinet/in.h> +#include <unistd.h> + +/** + * rpcsvc_drc_op_destroy - Destroys the cached reply + * + * @param drc - the main drc structure + * @param reply - the cached reply to destroy + * @return NULL if reply is destroyed, reply otherwise + */ +static drc_cached_op_t * +rpcsvc_drc_op_destroy (rpcsvc_drc_globals_t *drc, drc_cached_op_t *reply) +{ +        GF_ASSERT (drc); +        GF_ASSERT (reply); + +        if (reply->state == DRC_OP_IN_TRANSIT) +                return reply; + +        iobref_unref (reply->msg.iobref); +        if (reply->msg.rpchdr) +                GF_FREE (reply->msg.rpchdr); +        if (reply->msg.proghdr) +                GF_FREE (reply->msg.proghdr); +        if (reply->msg.progpayload) +                GF_FREE (reply->msg.progpayload); + +        list_del (&reply->global_list); +        reply->client->op_count--; +        drc->op_count--; +        mem_put (reply); +        reply = NULL; + +        return reply; +} + +/** + * rpcsvc_drc_op_rb_unref - This function is used in rb tree cleanup only + * + * @param reply - the cached reply to unref + * @param drc - the main drc structure + * @return void + */ +static void +rpcsvc_drc_rb_op_destroy (void *reply, void *drc) +{ +        rpcsvc_drc_op_destroy (drc, (drc_cached_op_t *)reply); +} + +/** + * rpcsvc_remove_drc_client - Cleanup the drc client + * + * @param client - the drc client to be removed + * @return void + */ +static void +rpcsvc_remove_drc_client (drc_client_t *client) +{ +        rb_destroy (client->rbtree, rpcsvc_drc_rb_op_destroy); +        list_del (&client->client_list); +        GF_FREE (client); +} + +/** + * rpcsvc_client_lookup - Given a sockaddr_storage, find the client if it exists + * + * @param drc - the main drc structure + * @param sockaddr - the network address of the client to be looked up + * @return drc client if it exists, NULL otherwise + */ +static drc_client_t * +rpcsvc_client_lookup (rpcsvc_drc_globals_t *drc, +                      struct sockaddr_storage *sockaddr) +{ +        drc_client_t    *client = NULL; + +        GF_ASSERT (drc); +        GF_ASSERT (sockaddr); + +        if (list_empty (&drc->clients_head)) +            return NULL; + +        list_for_each_entry (client, &drc->clients_head, client_list) { +                if (gf_sock_union_equal_addr (&client->sock_union, +                                              (union gf_sock_union *)sockaddr)) +                        return client; +        } + +        return NULL; +} + +/** + * drc_compare_reqs - Used by rbtree to determine if incoming req matches with + *                    an existing node(cached reply) in rbtree + * + * @param item - pointer to the incoming req + * @param rb_node_data - pointer to an rbtree node (cached reply) + * @param param - drc pointer - unused here, but used in *op_destroy + * @return 0 if req matches reply, else (req->xid - reply->xid) + */ +int +drc_compare_reqs (const void *item, const void *rb_node_data, void *param) +{ +        int               ret      = -1; +        rpcsvc_request_t *req      = NULL; +        drc_cached_op_t  *reply    = NULL; + +        GF_ASSERT (item); +        GF_ASSERT (rb_node_data); +        GF_ASSERT (param); + +        req = (rpcsvc_request_t *)item; +        reply = (drc_cached_op_t *)rb_node_data; + +        ret = req->xid - reply->xid; +        if (ret != 0) +                return ret; + +        if (req->prognum == reply->prognum && +            req->procnum == reply->procnum && +            req->progver == reply->progversion) +                return 0; + +        return 1; +} + +/** + * drc_rb_calloc - used by rbtree api to allocate memory for nodes + * + * @param allocator - the libavl_allocator structure used by rbtree + * @param size - not needed by this function + * @return pointer to new cached reply (node in rbtree) + */ +static void * +drc_rb_calloc (struct libavl_allocator *allocator, size_t size) +{ +        rpcsvc_drc_globals_t *drc = NULL; + +        /* get the drc pointer by simple typecast, since allocator +         * is the first member of rpcsvc_drc_globals_t +         */ +        drc = (rpcsvc_drc_globals_t *)allocator; + +        return mem_get (drc->mempool); +} + +/** + * drc_rb_free - used by rbtree api to free a node + * + * @param a - the libavl_allocator structure used by rbtree api + * @param block - node that needs to be freed + * @return void + */ +static void +drc_rb_free (struct libavl_allocator *a, void *block) +{ +        mem_put (block); +} + +/** + * drc_init_client_cache - initialize a drc client and its rb tree + * + * @param drc - the main drc structure + * @param client - the drc client to be initialized + * @return 0 on success, -1 on failure + */ +static int +drc_init_client_cache (rpcsvc_drc_globals_t *drc, drc_client_t *client) +{ +        GF_ASSERT (drc); +        GF_ASSERT (client); + +        drc->allocator.libavl_malloc = drc_rb_calloc; +        drc->allocator.libavl_free = drc_rb_free; + +        client->rbtree = rb_create (drc_compare_reqs, drc, +                                    (struct libavl_allocator *)drc); +        if (!client->rbtree) { +                gf_log (GF_RPCSVC, GF_LOG_DEBUG, "rb tree creation failed"); +                return -1; +        } + +        return 0; +} + +/** + * rpcsvc_get_drc_client - find the drc client with given sockaddr, else + *                         allocate and initialize a new drc client + * + * @param drc - the main drc structure + * @param sockaddr - network address of client + * @return drc client on success, NULL on failure + */ +static drc_client_t * +rpcsvc_get_drc_client (rpcsvc_drc_globals_t *drc, +                       struct sockaddr_storage *sockaddr) +{ +        drc_client_t      *client      = NULL; + +        GF_ASSERT (drc); +        GF_ASSERT (sockaddr); + +        client = rpcsvc_client_lookup (drc, sockaddr); +        if (client) +                goto out; + +        /* if lookup fails, allocate cache for the new client */ +        client = GF_CALLOC (1, sizeof (drc_client_t), +                            gf_common_mt_drc_client_t); +        if (!client) +                goto out; + +        client->ref = 0; +        client->sock_union = (union gf_sock_union)*sockaddr; +        client->op_count = 0; + +        if (drc_init_client_cache (drc, client)) { +                gf_log (GF_RPCSVC, GF_LOG_DEBUG, +                        "initialization of drc client failed"); +                GF_FREE (client); +                client = NULL; +                goto out; +        } +        drc->client_count++; + +        list_add (&client->client_list, &drc->clients_head); + + out: +        return client; +} + +/** + * rpcsvc_need_drc - Determine if a request needs DRC service + * + * @param req - incoming request + * @return 1 if DRC is needed for req, 0 otherwise + */ +int +rpcsvc_need_drc (rpcsvc_request_t *req) +{ +        rpcsvc_actor_t           *actor = NULL; +        rpcsvc_drc_globals_t     *drc   = NULL; + +        GF_ASSERT (req); +        GF_ASSERT (req->svc); + +        drc = req->svc->drc; + +        if (!drc || drc->status == DRC_UNINITIATED) +                return 0; + +        actor = rpcsvc_program_actor (req); +        if (!actor) +                return 0; + +        return (actor->op_type == DRC_NON_IDEMPOTENT +                && drc->type != DRC_TYPE_NONE); +} + +/** + * rpcsvc_drc_client_ref - ref the drc client + * + * @param client - the drc client to ref + * @return client + */ +static drc_client_t * +rpcsvc_drc_client_ref (drc_client_t *client) +{ +        GF_ASSERT (client); +        client->ref++; +        return client; +} + +/** + * rpcsvc_drc_client_unref - unref the drc client, and destroy + *                           the client on last unref + * + * @param drc - the main drc structure + * @param client - the drc client to unref + * @return NULL if it is the last unref, client otherwise + */ +static drc_client_t * +rpcsvc_drc_client_unref (rpcsvc_drc_globals_t *drc, drc_client_t *client) +{ +        GF_ASSERT (drc); +        GF_ASSERT (client->ref); + +        client->ref--; +        if (!client->ref) { +                drc->client_count--; +                rpcsvc_remove_drc_client (client); +                client = NULL; +        } + +        return client; +} + +/** + * rpcsvc_drc_lookup - lookup a request to see if it is already cached + * + * @param req - incoming request + * @return cached reply of req if found, NULL otherwise + */ +drc_cached_op_t * +rpcsvc_drc_lookup (rpcsvc_request_t *req) +{ +        drc_client_t           *client = NULL; +        drc_cached_op_t        *reply  = NULL; + +        GF_ASSERT (req); + +        if (!req->trans->drc_client) { +                client = rpcsvc_get_drc_client (req->svc->drc, +                                                &req->trans->peerinfo.sockaddr); +                if (!client) +                        goto out; +                req->trans->drc_client = client; +        } + +        client = rpcsvc_drc_client_ref (req->trans->drc_client); + +        if (client->op_count == 0) +                goto out; + +        reply = rb_find (client->rbtree, req); + + out: +        if (client) +                rpcsvc_drc_client_unref (req->svc->drc, client); + +        return reply; +} + +/** + * rpcsvc_send_cached_reply - send the cached reply for the incoming request + * + * @param req - incoming request (which is a duplicate in this case) + * @param reply - the cached reply for req + * @return 0 on successful reply submission, -1 or other non-zero value otherwise + */ +int +rpcsvc_send_cached_reply (rpcsvc_request_t *req, drc_cached_op_t *reply) +{ +        int     ret = 0; + +        GF_ASSERT (req); +        GF_ASSERT (reply); + +        gf_log (GF_RPCSVC, GF_LOG_DEBUG, "sending cached reply: xid: %d, " +                "client: %s", req->xid, req->trans->peerinfo.identifier); + +        rpcsvc_drc_client_ref (reply->client); +        ret = rpcsvc_transport_submit (req->trans, +                     reply->msg.rpchdr, reply->msg.rpchdrcount, +                     reply->msg.proghdr, reply->msg.proghdrcount, +                     reply->msg.progpayload, reply->msg.progpayloadcount, +                     reply->msg.iobref, req->trans_private); +        rpcsvc_drc_client_unref (req->svc->drc, reply->client); + +        return ret; +} + +/** + * rpcsvc_cache_reply - cache the reply for the processed request 'req' + * + * @param req - processed request + * @param iobref - iobref structure of the reply + * @param rpchdr - rpc header of the reply + * @param rpchdrcount - size of rpchdr + * @param proghdr - program header of the reply + * @param proghdrcount - size of proghdr + * @param payload - payload of the reply if any + * @param payloadcount - size of payload + * @return 0 on success, -1 on failure + */ +int +rpcsvc_cache_reply (rpcsvc_request_t *req, struct iobref *iobref, +                    struct iovec *rpchdr, int rpchdrcount, +                    struct iovec *proghdr, int proghdrcount, +                    struct iovec *payload, int payloadcount) +{ +        int                       ret              = -1; +        drc_cached_op_t          *reply            = NULL; + +        GF_ASSERT (req); +        GF_ASSERT (req->reply); + +        reply = req->reply; + +        reply->state = DRC_OP_CACHED; + +        reply->msg.iobref = iobref_ref (iobref); + +        reply->msg.rpchdrcount = rpchdrcount; +        reply->msg.rpchdr = iov_dup (rpchdr, rpchdrcount); + +        reply->msg.proghdrcount = proghdrcount; +        reply->msg.proghdr = iov_dup (proghdr, proghdrcount); + +        reply->msg.progpayloadcount = payloadcount; +        if (payloadcount) +                reply->msg.progpayload = iov_dup (payload, payloadcount); + +        //        rpcsvc_drc_client_unref (req->svc->drc, req->trans->drc_client); +        //        rpcsvc_drc_op_unref (req->svc->drc, reply); +        ret = 0; + +        return ret; +} + +/** + * rpcsvc_vacate_drc_entries - free up some percentage of drc cache + *                             based on the lru factor + * + * @param drc - the main drc structure + * @return void + */ +static void +rpcsvc_vacate_drc_entries (rpcsvc_drc_globals_t *drc) +{ +        uint32_t            i           = 0; +        uint32_t            n           = 0; +        drc_cached_op_t    *reply       = NULL; +        drc_cached_op_t    *tmp         = NULL; +        drc_client_t       *client      = NULL; + +        GF_ASSERT (drc); + +        n = drc->global_cache_size / drc->lru_factor; + +        list_for_each_entry_safe_reverse (reply, tmp, &drc->cache_head, global_list) { +                /* Don't delete ops that are in transit */ +                if (reply->state == DRC_OP_IN_TRANSIT) +                        continue; + +                client = reply->client; + +                (void *)rb_delete (client->rbtree, reply); + +                rpcsvc_drc_op_destroy (drc, reply); +                rpcsvc_drc_client_unref (drc, client); +                i++; +                if (i >= n) +                        break; +        } +} + +/** + * rpcsvc_add_op_to_cache - insert the cached op into the client rbtree and drc list + * + * @param drc - the main drc structure + * @param reply - the op to be inserted + * @return 0 on success, -1 on failure + */ +static int +rpcsvc_add_op_to_cache (rpcsvc_drc_globals_t *drc, drc_cached_op_t *reply) +{ +        drc_client_t        *client         = NULL; +        drc_cached_op_t    **tmp_reply      = NULL; + +        GF_ASSERT (drc); +        GF_ASSERT (reply); + +        client = reply->client; + +        /* cache is full, free up some space */ +        if (drc->op_count >= drc->global_cache_size) +                rpcsvc_vacate_drc_entries (drc); + +        tmp_reply = (drc_cached_op_t **)rb_probe (client->rbtree, reply); +        if (*tmp_reply != reply) { +                /* should never happen */ +                gf_log (GF_RPCSVC, GF_LOG_ERROR, +                        "DRC failed to detect duplicates"); +                return -1; +        } else if (*tmp_reply == NULL) { +                /* mem alloc failed */ +                return -1; +        } + +        client->op_count++; +        list_add (&reply->global_list, &drc->cache_head); +        drc->op_count++; + +        return 0; +} + +/** + * rpcsvc_cache_request - cache the in-transition incoming request + * + * @param req - incoming request + * @return 0 on success, -1 on failure + */ +int +rpcsvc_cache_request (rpcsvc_request_t *req) +{ +        int                        ret            = -1; +        drc_client_t              *client         = NULL; +        drc_cached_op_t           *reply          = NULL; +        rpcsvc_drc_globals_t      *drc            = NULL; + +        GF_ASSERT (req); + +        drc = req->svc->drc; + +        client = req->trans->drc_client; +        if (!client) { +                gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc client is NULL"); +                goto out; +        } + +        reply = mem_get (drc->mempool); +        if (!reply) +                goto out; + +        reply->client = rpcsvc_drc_client_ref (client); +        reply->xid = req->xid; +        reply->prognum = req->prognum; +        reply->progversion = req->progver; +        reply->procnum = req->procnum; +        reply->state = DRC_OP_IN_TRANSIT; +        req->reply = reply; + +        ret = rpcsvc_add_op_to_cache (drc, reply); +        if (ret) { +                req->reply = NULL; +                rpcsvc_drc_op_destroy (drc, reply); +                rpcsvc_drc_client_unref (drc, client); +                gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Failed to add op to drc cache"); +        } + + out: +        return ret; +} + +/** + * + * rpcsvc_drc_priv - function which dumps the drc state + * + * @param drc - the main drc structure + * @return 0 on success, -1 on failure + */ +int32_t +rpcsvc_drc_priv (rpcsvc_drc_globals_t *drc) +{ +        int                      i                         = 0; +        char                     key[GF_DUMP_MAX_BUF_LEN]  = {0}; +        drc_client_t            *client                    = NULL; +        char                     ip[INET6_ADDRSTRLEN]      = {0}; + +        if (!drc || drc->status == DRC_UNINITIATED) { +                gf_log (GF_RPCSVC, GF_LOG_DEBUG, "DRC is " +                        "uninitialized, not dumping its state"); +                return 0; +        } + +        gf_proc_dump_add_section("rpc.drc"); + +        if (TRY_LOCK (&drc->lock)) +                return -1; + +        gf_proc_dump_build_key (key, "drc", "type"); +        gf_proc_dump_write (key, "%d", drc->type); + +        gf_proc_dump_build_key (key, "drc", "client_count"); +        gf_proc_dump_write (key, "%d", drc->client_count); + +        gf_proc_dump_build_key (key, "drc", "current_cache_size"); +        gf_proc_dump_write (key, "%d", drc->op_count); + +        gf_proc_dump_build_key (key, "drc", "max_cache_size"); +        gf_proc_dump_write (key, "%d", drc->global_cache_size); + +        gf_proc_dump_build_key (key, "drc", "lru_factor"); +        gf_proc_dump_write (key, "%d", drc->lru_factor); + +        gf_proc_dump_build_key (key, "drc", "duplicate_request_count"); +        gf_proc_dump_write (key, "%d", drc->cache_hits); + +        gf_proc_dump_build_key (key, "drc", "in_transit_duplicate_requests"); +        gf_proc_dump_write (key, "%d", drc->intransit_hits); + +        list_for_each_entry (client, &drc->clients_head, client_list) { +                gf_proc_dump_build_key (key, "client", "%d.ip-address", i); +                memset (ip, 0, INET6_ADDRSTRLEN); +                switch (client->sock_union.storage.ss_family) { +                case AF_INET: +                        gf_proc_dump_write (key, "%s", inet_ntop (AF_INET, +                                &client->sock_union.sin.sin_addr.s_addr, +                                ip, INET_ADDRSTRLEN)); +                        break; +                case AF_INET6: +                        gf_proc_dump_write (key, "%s", inet_ntop (AF_INET6, +                                &client->sock_union.sin6.sin6_addr, +                                ip, INET6_ADDRSTRLEN)); +                        break; +                default: +                        gf_proc_dump_write (key, "%s", "N/A"); +                } + +                gf_proc_dump_build_key (key, "client", "%d.ref_count", i); +                gf_proc_dump_write (key, "%d", client->ref); +                gf_proc_dump_build_key (key, "client", "%d.op_count", i); +                gf_proc_dump_write (key, "%d", client->op_count); +                i++; +        } + +        UNLOCK (&drc->lock); +        return 0; +} + +/** + * rpcsvc_drc_notify - function which is notified of RPC transport events + * + * @param svc - pointer to rpcsvc_t structure of the rpc + * @param xl - pointer to the xlator + * @param event - the event which triggered this notify + * @param data - the transport structure + * @return 0 on success, -1 on failure + */ +int +rpcsvc_drc_notify (rpcsvc_t *svc, void *xl, +                   rpcsvc_event_t event, void *data) +{ +        int                       ret          = -1; +        rpc_transport_t          *trans        = NULL; +        drc_client_t             *client       = NULL; +        rpcsvc_drc_globals_t     *drc          = NULL; + +        GF_ASSERT (svc); +        GF_ASSERT (svc->drc); +        GF_ASSERT (data); + +        drc = svc->drc; + +        if (drc->status == DRC_UNINITIATED || +            drc->type == DRC_TYPE_NONE) +                return 0; + +        LOCK (&drc->lock); + +        trans = (rpc_transport_t *)data; +        client = rpcsvc_get_drc_client (drc, &trans->peerinfo.sockaddr); +        if (!client) +                goto out; + +        switch (event) { +        case RPCSVC_EVENT_ACCEPT: +                trans->drc_client = rpcsvc_drc_client_ref (client); +                ret = 0; +                break; + +        case RPCSVC_EVENT_DISCONNECT: +                ret = 0; +                if (list_empty (&drc->clients_head)) +                        break; +                /* should be the last unref */ +                rpcsvc_drc_client_unref (drc, client); +                trans->drc_client = NULL; +                break; + +        default: +                break; +        } + + out: +        UNLOCK (&drc->lock); +        return ret; +} + +/** + * rpcsvc_drc_init - Initialize the duplicate request cache service + * + * @param svc - pointer to rpcsvc_t structure of the rpc + * @param options - the options dictionary which configures drc + * @return 0 on success, non-zero integer on failure + */ +int +rpcsvc_drc_init (rpcsvc_t *svc, dict_t *options) +{ +        int                         ret            = 0; +        uint32_t                    drc_type       = 0; +        uint32_t                    drc_size       = 0; +        uint32_t                    drc_factor     = 0; +        rpcsvc_drc_globals_t       *drc            = NULL; + +        GF_ASSERT (svc); +        GF_ASSERT (options); + +        if (!svc->drc) { +                drc = GF_CALLOC (1, sizeof (rpcsvc_drc_globals_t), +                                 gf_common_mt_drc_globals_t); +                if (!drc) +                        return -1; + +                svc->drc = drc; +                LOCK_INIT (&drc->lock); +        } else { +                drc = svc->drc; +        } + +        LOCK (&drc->lock); +        if (drc->type != DRC_TYPE_NONE) { +                ret = 0; +                goto out; +        } + +        /* Toggle DRC on/off, when more drc types(persistent/cluster) +           are added, we shouldn't treat this as boolean */ +        ret = dict_get_str_boolean (options, "nfs.drc", _gf_false); +        if (ret == -1) { +                gf_log (GF_RPCSVC, GF_LOG_INFO, "drc user options need second look"); +                ret = _gf_true; +        } + +        if (ret == _gf_false) { +                /* drc off */ +                gf_log (GF_RPCSVC, GF_LOG_DEBUG, "DRC is off"); +                ret = 0; +                goto out; +        } + +        /* Specify type of DRC to be used */ +        ret = dict_get_uint32 (options, "nfs.drc-type", &drc_type); +        if (ret) { +                gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc type not set." +                        " Continuing with default"); +                drc_type = DRC_DEFAULT_TYPE; +        } + +        drc->type = drc_type; + +        /* Set the global cache size (no. of ops to cache) */ +        ret = dict_get_uint32 (options, "nfs.drc-size", &drc_size); +        if (ret) { +                gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc size not set." +                        " Continuing with default size"); +                drc_size = DRC_DEFAULT_CACHE_SIZE; +        } + +        drc->global_cache_size = drc_size; + +        /* Mempool for cached ops */ +        drc->mempool = mem_pool_new (drc_cached_op_t, drc->global_cache_size); +        if (!drc->mempool) { +                gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get mempool for" +                        " DRC, drc-size: %d", drc->global_cache_size); +                ret = -1; +                goto out; +        } + +        /* What percent of cache to be evicted whenever it fills up */ +        ret = dict_get_uint32 (options, "nfs.drc-lru-factor", &drc_factor); +        if (ret) { +                gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc lru factor not set." +                        " Continuing with policy default"); +                drc_factor = DRC_DEFAULT_LRU_FACTOR; +        } + +        drc->lru_factor = (drc_lru_factor_t) drc_factor; + +        INIT_LIST_HEAD (&drc->clients_head); +        INIT_LIST_HEAD (&drc->cache_head); + +        ret = rpcsvc_register_notify (svc, rpcsvc_drc_notify, THIS); +        if (ret) { +                gf_log (GF_RPCSVC, GF_LOG_ERROR, +                        "registration of drc_notify function failed"); +                goto out; +        } + +        gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc init successful"); +        drc->status = DRC_INITIATED; + + out: +        UNLOCK (&drc->lock); +        if (ret == -1) { +                if (drc->mempool) { +                        mem_pool_destroy (drc->mempool); +                        drc->mempool = NULL; +                } +                GF_FREE (drc); +                svc->drc = NULL; +        } +        return ret; +} diff --git a/rpc/rpc-lib/src/rpc-drc.h b/rpc/rpc-lib/src/rpc-drc.h new file mode 100644 index 00000000000..0a1688992d5 --- /dev/null +++ b/rpc/rpc-lib/src/rpc-drc.h @@ -0,0 +1,100 @@ +/* +  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 RPC_DRC_H +#define RPC_DRC_H + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "rpcsvc-common.h" +#include "rpcsvc.h" +#include "locking.h" +#include "dict.h" +#include "rb.h" + +/* per-client cache structure */ +struct drc_client { +        uint32_t                   ref; +        union gf_sock_union        sock_union; +        /* pointers to the cache */ +        struct rb_table           *rbtree; +        /* no. of ops currently cached */ +        uint32_t                   op_count; +        struct list_head           client_list; +}; + +struct drc_cached_op { +        drc_op_state_t                 state; +        uint32_t                       xid; +        int                            prognum; +        int                            progversion; +        int                            procnum; +        rpc_transport_msg_t            msg; +        drc_client_t                  *client; +        struct list_head               client_list; +        struct list_head               global_list; +        int32_t                        ref; +}; + +/* global drc definitions */ +enum drc_status { +        DRC_UNINITIATED, +        DRC_INITIATED +}; +typedef enum drc_status drc_status_t; + +struct drc_globals { +        /* allocator must be the first member since +         * it is used so in gf_libavl_allocator +         */ +        struct libavl_allocator   allocator; +        drc_type_t                type; +        /* configurable size parameter */ +        uint32_t                  global_cache_size; +        drc_lru_factor_t          lru_factor; +        gf_lock_t                 lock; +        drc_status_t              status; +        uint32_t                  op_count; +        uint64_t                  cache_hits; +        uint64_t                  intransit_hits; +        struct mem_pool          *mempool; +        struct list_head          cache_head; +        uint32_t                  client_count; +        struct list_head          clients_head; +}; + +int +rpcsvc_need_drc (rpcsvc_request_t *req); + +drc_cached_op_t * +rpcsvc_drc_lookup (rpcsvc_request_t *req); + +int +rpcsvc_send_cached_reply (rpcsvc_request_t *req, drc_cached_op_t *reply); + +int +rpcsvc_cache_reply (rpcsvc_request_t *req, struct iobref *iobref, +                    struct iovec *rpchdr, int rpchdrcount, +                    struct iovec *proghdr, int proghdrcount, +                    struct iovec *payload, int payloadcount); + +int +rpcsvc_cache_request (rpcsvc_request_t *req); + +int32_t +rpcsvc_drc_priv (rpcsvc_drc_globals_t *drc); + +int +rpcsvc_drc_init (rpcsvc_t *svc, dict_t *options); + +#endif /* RPC_DRC_H */ diff --git a/rpc/rpc-lib/src/rpc-transport.h b/rpc/rpc-lib/src/rpc-transport.h index a8744d61810..4384f2abdc6 100644 --- a/rpc/rpc-lib/src/rpc-transport.h +++ b/rpc/rpc-lib/src/rpc-transport.h @@ -196,6 +196,7 @@ struct rpc_transport {          dict_t                    *options;          char                      *name;          void                      *dnscache; +        void                      *drc_client;          data_t                    *buf;          int32_t                  (*init)   (rpc_transport_t *this);          void                     (*fini)   (rpc_transport_t *this); diff --git a/rpc/rpc-lib/src/rpcsvc-common.h b/rpc/rpc-lib/src/rpcsvc-common.h index 2c6f074886d..054e187c96d 100644 --- a/rpc/rpc-lib/src/rpcsvc-common.h +++ b/rpc/rpc-lib/src/rpcsvc-common.h @@ -30,6 +30,8 @@ struct rpcsvc_state;  typedef int (*rpcsvc_notify_t) (struct rpcsvc_state *, void *mydata,                                  rpcsvc_event_t, void *data); +struct drc_globals; +typedef struct drc_globals rpcsvc_drc_globals_t;  /* Contains global state required for all the RPC services.   */ @@ -68,7 +70,53 @@ typedef struct rpcsvc_state {          void                    *mydata; /* This is xlator */          rpcsvc_notify_t          notifyfn;          struct mem_pool         *rxpool; +        rpcsvc_drc_globals_t    *drc;  } rpcsvc_t; +/* DRC START */ +enum drc_op_type { +        DRC_NA              = 0, +        DRC_IDEMPOTENT      = 1, +        DRC_NON_IDEMPOTENT  = 2 +}; +typedef enum drc_op_type drc_op_type_t; + +enum drc_type { +        DRC_TYPE_NONE        = 0, +        DRC_TYPE_IN_MEMORY   = 1 +}; +typedef enum drc_type drc_type_t; + +enum drc_lru_factor { +        DRC_LRU_5_PC       = 20, +        DRC_LRU_10_PC      = 10, +        DRC_LRU_25_PC      = 4, +        DRC_LRU_50_PC      = 2 +}; +typedef enum drc_lru_factor drc_lru_factor_t; + +enum drc_xid_state { +        DRC_XID_MONOTONOUS  = 0, +        DRC_XID_WRAPPED     = 1 +}; +typedef enum drc_xid_state drc_xid_state_t; + +enum drc_op_state { +        DRC_OP_IN_TRANSIT    = 0, +        DRC_OP_CACHED        = 1 +}; +typedef enum drc_op_state drc_op_state_t; + +enum drc_policy { +        DRC_LRU              = 0 +}; +typedef enum drc_policy drc_policy_t; + +/* Default policies for DRC */ +#define DRC_DEFAULT_TYPE               DRC_TYPE_IN_MEMORY +#define DRC_DEFAULT_CACHE_SIZE         0x20000 +#define DRC_DEFAULT_LRU_FACTOR         DRC_LRU_25_PC + +/* DRC END */  #endif /* #ifndef _RPCSVC_COMMON_H */ diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c index d69756cc004..7efb2e1fbb7 100644 --- a/rpc/rpc-lib/src/rpcsvc.c +++ b/rpc/rpc-lib/src/rpcsvc.c @@ -28,6 +28,7 @@  #include "xdr-generic.h"  #include "rpc-common-xdr.h"  #include "syncop.h" +#include "rpc-drc.h"  #include <errno.h>  #include <pthread.h> @@ -422,6 +423,7 @@ rpcsvc_request_create (rpcsvc_t *svc, rpc_transport_t *trans,           * since we are not handling authentication failures for now.           */          req->rpc_status = MSG_ACCEPTED; +        req->reply = NULL;          ret = 0;  err:          if (ret == -1) { @@ -461,13 +463,15 @@ int  rpcsvc_handle_rpc_call (rpcsvc_t *svc, rpc_transport_t *trans,                          rpc_transport_pollin_t *msg)  { -        rpcsvc_actor_t          *actor = NULL; -        rpcsvc_actor            actor_fn = NULL; -        rpcsvc_request_t        *req = NULL; -        int                     ret = -1; -        uint16_t                port = 0; -        gf_boolean_t            is_unix = _gf_false; -        gf_boolean_t            unprivileged = _gf_false; +        rpcsvc_actor_t         *actor          = NULL; +        rpcsvc_actor            actor_fn       = NULL; +        rpcsvc_request_t       *req            = NULL; +        int                     ret            = -1; +        uint16_t                port           = 0; +        gf_boolean_t            is_unix        = _gf_false; +        gf_boolean_t            unprivileged   = _gf_false; +        drc_cached_op_t        *reply          = NULL; +        rpcsvc_drc_globals_t   *drc            = NULL;          if (!trans || !svc)                  return -1; @@ -503,7 +507,7 @@ rpcsvc_handle_rpc_call (rpcsvc_t *svc, rpc_transport_t *trans,          req = rpcsvc_request_create (svc, trans, msg);          if (!req) -                goto err; +                goto out;          if (!rpcsvc_request_accepted (req))                  goto err_reply; @@ -521,6 +525,39 @@ rpcsvc_handle_rpc_call (rpcsvc_t *svc, rpc_transport_t *trans,                          return -1;          } +        /* DRC */ +        if (rpcsvc_need_drc (req)) { +                drc = req->svc->drc; + +                LOCK (&drc->lock); +                reply = rpcsvc_drc_lookup (req); + +                /* retransmission of completed request, send cached reply */ +                if (reply && reply->state == DRC_OP_CACHED) { +                        gf_log (GF_RPCSVC, GF_LOG_INFO, "duplicate request:" +                                " XID: 0x%x", req->xid); +                        ret = rpcsvc_send_cached_reply (req, reply); +                        drc->cache_hits++; +                        UNLOCK (&drc->lock); +                        goto out; + +                } /* retransmitted request, original op in transit, drop it */ +                else if (reply && reply->state == DRC_OP_IN_TRANSIT) { +                        gf_log (GF_RPCSVC, GF_LOG_INFO, "op in transit," +                                " discarding. XID: 0x%x", req->xid); +                        ret = 0; +                        drc->intransit_hits++; +                        rpcsvc_request_destroy (req); +                        UNLOCK (&drc->lock); +                        goto out; + +                } /* fresh request, cache it as in-transit and proceed */ +                else { +                        ret = rpcsvc_cache_request (req); +                } +                UNLOCK (&drc->lock); +        } +          if (req->rpc_err == SUCCESS) {                  /* Before going to xlator code, set the THIS properly */                  THIS = svc->mydata; @@ -557,7 +594,7 @@ err_reply:           * has now been queued. */          ret = 0; -err: +out:          return ret;  } @@ -904,21 +941,22 @@ out:          return ret;  } -static inline int -rpcsvc_transport_submit (rpc_transport_t *trans, struct iovec *hdrvec, -                         int hdrcount, struct iovec *proghdr, int proghdrcount, -                         struct iovec *progpayload, int progpayloadcount, -                         struct iobref *iobref, void *priv) +int +rpcsvc_transport_submit (rpc_transport_t *trans, struct iovec *rpchdr, +                         int rpchdrcount, struct iovec *proghdr, +                         int proghdrcount, struct iovec *progpayload, +                         int progpayloadcount, struct iobref *iobref, +                         void *priv)  {          int                   ret   = -1;          rpc_transport_reply_t reply = {{0, }}; -        if ((!trans) || (!hdrvec) || (!hdrvec->iov_base)) { +        if ((!trans) || (!rpchdr) || (!rpchdr->iov_base)) {                  goto out;          } -        reply.msg.rpchdr = hdrvec; -        reply.msg.rpchdrcount = hdrcount; +        reply.msg.rpchdr = rpchdr; +        reply.msg.rpchdrcount = rpchdrcount;          reply.msg.proghdr = proghdr;          reply.msg.proghdrcount = proghdrcount;          reply.msg.progpayload = progpayload; @@ -1064,6 +1102,7 @@ rpcsvc_submit_generic (rpcsvc_request_t *req, struct iovec *proghdr,          size_t                  msglen     = 0;          size_t                  hdrlen     = 0;          char                    new_iobref = 0; +        rpcsvc_drc_globals_t   *drc        = NULL;          if ((!req) || (!req->trans))                  return -1; @@ -1098,6 +1137,17 @@ rpcsvc_submit_generic (rpcsvc_request_t *req, struct iovec *proghdr,          iobref_add (iobref, replyiob); +        /* cache the request in the duplicate request cache for appropriate ops */ +        if (req->reply) { +                drc = req->svc->drc; + +                LOCK (&drc->lock); +                ret = rpcsvc_cache_reply (req, iobref, &recordhdr, 1, +                                          proghdr, hdrcount, +                                          payload, payloadcount); +                UNLOCK (&drc->lock); +        } +          ret = rpcsvc_transport_submit (trans, &recordhdr, 1, proghdr, hdrcount,                                         payload, payloadcount, iobref,                                         req->trans_private); @@ -1905,6 +1955,7 @@ rpcsvc_init (xlator_t *xl, glusterfs_ctx_t *ctx, dict_t *options,                          "failed to register DUMP program");                  goto free_svc;          } +          ret = 0;  free_svc:          if (ret == -1) { @@ -2196,9 +2247,9 @@ out:  rpcsvc_actor_t gluster_dump_actors[] = { -        [GF_DUMP_NULL] = {"NULL", GF_DUMP_NULL, NULL, NULL, 0}, -        [GF_DUMP_DUMP] = {"DUMP", GF_DUMP_DUMP, rpcsvc_dump, NULL, 0}, -        [GF_DUMP_MAXVALUE] = {"MAXVALUE", GF_DUMP_MAXVALUE, NULL, NULL, 0}, +        [GF_DUMP_NULL]      = {"NULL",     GF_DUMP_NULL,     NULL,        NULL, 0, DRC_NA}, +        [GF_DUMP_DUMP]      = {"DUMP",     GF_DUMP_DUMP,     rpcsvc_dump, NULL, 0, DRC_NA}, +        [GF_DUMP_MAXVALUE]  = {"MAXVALUE", GF_DUMP_MAXVALUE, NULL,        NULL, 0, DRC_NA},  }; diff --git a/rpc/rpc-lib/src/rpcsvc.h b/rpc/rpc-lib/src/rpcsvc.h index afa7c992634..67ff74be6bc 100644 --- a/rpc/rpc-lib/src/rpcsvc.h +++ b/rpc/rpc-lib/src/rpcsvc.h @@ -140,6 +140,9 @@ typedef struct rpcsvc_auth_data {  #define rpcsvc_auth_flavour(au)    ((au).flavour) +typedef struct drc_client drc_client_t; +typedef struct drc_cached_op drc_cached_op_t; +  /* The container for the RPC call handed up to an actor.   * Dynamically allocated. Lives till the call reply is completely   * transmitted. @@ -241,6 +244,9 @@ struct rpcsvc_request {          /* we need to ref the 'iobuf' in case of 'synctasking' it */          struct iobuf            *hdr_iobuf; + +        /* pointer to cached reply for use in DRC */ +        drc_cached_op_t         *reply;  };  #define rpcsvc_request_program(req) ((rpcsvc_program_t *)((req)->prog)) @@ -314,7 +320,6 @@ typedef void *(*rpcsvc_encode_reply) (void *msg);   */  typedef void (*rpcsvc_deallocate_reply) (void *msg); -  #define RPCSVC_NAME_MAX            32  /* The descriptor for each procedure/actor that runs   * over the RPC service. @@ -336,6 +341,7 @@ typedef struct rpcsvc_actor_desc {          /* Can actor be ran on behalf an unprivileged requestor? */          gf_boolean_t            unprivileged; +        drc_op_type_t           op_type;  } rpcsvc_actor_t;  /* Describes a program and its version along with the function pointers @@ -448,6 +454,13 @@ int  rpcsvc_unregister_notify (rpcsvc_t *svc, rpcsvc_notify_t notify, void *mydata);  int +rpcsvc_transport_submit (rpc_transport_t *trans, struct iovec *rpchdr, +                         int rpchdrcount, struct iovec *proghdr, +                         int proghdrcount, struct iovec *progpayload, +                         int progpayloadcount, struct iobref *iobref, +                         void *priv); + +int  rpcsvc_submit_message (rpcsvc_request_t *req, struct iovec *proghdr,                         int hdrcount, struct iovec *payload, int payloadcount,                         struct iobref *iobref); @@ -558,6 +571,9 @@ int rpcsvc_callback_submit (rpcsvc_t *rpc, rpc_transport_t *trans,                              rpcsvc_cbk_program_t *prog, int procnum,                              struct iovec *proghdr, int proghdrcount); +rpcsvc_actor_t * +rpcsvc_program_actor (rpcsvc_request_t *req); +  int  rpcsvc_transport_unix_options_build (dict_t **options, char *filepath);  int @@ -571,5 +587,4 @@ rpcsvc_volume_allowed (dict_t *options, char *volname);  rpcsvc_vector_sizer  rpcsvc_get_program_vector_sizer (rpcsvc_t *svc, uint32_t prognum,                                   uint32_t progver, uint32_t procnum); -  #endif diff --git a/rpc/xdr/src/xdr-nfs3.h b/rpc/xdr/src/xdr-nfs3.h index 964632be10d..6f6b0e1f9b0 100644 --- a/rpc/xdr/src/xdr-nfs3.h +++ b/rpc/xdr/src/xdr-nfs3.h @@ -1039,8 +1039,10 @@ typedef struct exportnode exportnode;  #define MOUNT3_PROC_COUNT       6  #define MOUNT1_NULL             0 +#define MOUNT1_MNT              1  #define MOUNT1_DUMP             2  #define MOUNT1_UMNT             3 +#define MOUNT1_UMNTALL          4  #define MOUNT1_EXPORT           5  #define MOUNT1_PROC_COUNT       6  /* the xdr functions */ diff --git a/tests/bugs/bug-847624.t b/tests/bugs/bug-847624.t new file mode 100755 index 00000000000..f4e9942e94b --- /dev/null +++ b/tests/bugs/bug-847624.t @@ -0,0 +1,23 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +cleanup + +#1 +TEST glusterd +TEST pidof glusterd +#3 +TEST $CLI volume create $V0 $H0:$B0/$V0 +TEST $CLI volume set $V0 nfs.drc on +TEST $CLI volume start $V0 +sleep 5 +TEST mount -t nfs -o vers=3,nolock,soft,intr $H0:/$V0 $N0 +cd $N0 +#7 +TEST dbench -t 10 10 +TEST rm -rf $N0/* +cd +TEST umount $N0 +#10 +TEST $CLI volume set $V0 nfs.drc-size 10000 +cleanup diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c index dd9e248cfab..7ae8b28beea 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handler.c +++ b/xlators/mgmt/glusterd/src/glusterd-handler.c @@ -3853,11 +3853,11 @@ glusterd_null (rpcsvc_request_t *req)  }  rpcsvc_actor_t gd_svc_mgmt_actors[] = { -        [GLUSTERD_MGMT_NULL]           = { "NULL", GLUSTERD_MGMT_NULL, glusterd_null, NULL, 0}, -        [GLUSTERD_MGMT_CLUSTER_LOCK]   = { "CLUSTER_LOCK", GLUSTERD_MGMT_CLUSTER_LOCK, glusterd_handle_cluster_lock, NULL, 0}, -        [GLUSTERD_MGMT_CLUSTER_UNLOCK] = { "CLUSTER_UNLOCK", GLUSTERD_MGMT_CLUSTER_UNLOCK, glusterd_handle_cluster_unlock, NULL, 0}, -        [GLUSTERD_MGMT_STAGE_OP]       = { "STAGE_OP", GLUSTERD_MGMT_STAGE_OP, glusterd_handle_stage_op, NULL, 0}, -        [GLUSTERD_MGMT_COMMIT_OP]      = { "COMMIT_OP", GLUSTERD_MGMT_COMMIT_OP, glusterd_handle_commit_op, NULL, 0}, +        [GLUSTERD_MGMT_NULL]           = { "NULL",           GLUSTERD_MGMT_NULL,           glusterd_null,                  NULL, 0, DRC_NA}, +        [GLUSTERD_MGMT_CLUSTER_LOCK]   = { "CLUSTER_LOCK",   GLUSTERD_MGMT_CLUSTER_LOCK,   glusterd_handle_cluster_lock,   NULL, 0, DRC_NA}, +        [GLUSTERD_MGMT_CLUSTER_UNLOCK] = { "CLUSTER_UNLOCK", GLUSTERD_MGMT_CLUSTER_UNLOCK, glusterd_handle_cluster_unlock, NULL, 0, DRC_NA}, +        [GLUSTERD_MGMT_STAGE_OP]       = { "STAGE_OP",       GLUSTERD_MGMT_STAGE_OP,       glusterd_handle_stage_op,       NULL, 0, DRC_NA}, +        [GLUSTERD_MGMT_COMMIT_OP]      = { "COMMIT_OP",      GLUSTERD_MGMT_COMMIT_OP,      glusterd_handle_commit_op,      NULL, 0, DRC_NA},  };  struct rpcsvc_program gd_svc_mgmt_prog = { @@ -3870,11 +3870,11 @@ struct rpcsvc_program gd_svc_mgmt_prog = {  };  rpcsvc_actor_t gd_svc_peer_actors[] = { -        [GLUSTERD_FRIEND_NULL]    = { "NULL", GLUSTERD_MGMT_NULL, glusterd_null, NULL, 0}, -        [GLUSTERD_PROBE_QUERY]    = { "PROBE_QUERY", GLUSTERD_PROBE_QUERY, glusterd_handle_probe_query, NULL, 0}, -        [GLUSTERD_FRIEND_ADD]     = { "FRIEND_ADD", GLUSTERD_FRIEND_ADD, glusterd_handle_incoming_friend_req, NULL, 0}, -        [GLUSTERD_FRIEND_REMOVE]  = { "FRIEND_REMOVE", GLUSTERD_FRIEND_REMOVE, glusterd_handle_incoming_unfriend_req, NULL, 0}, -        [GLUSTERD_FRIEND_UPDATE]  = { "FRIEND_UPDATE", GLUSTERD_FRIEND_UPDATE, glusterd_handle_friend_update, NULL, 0}, +        [GLUSTERD_FRIEND_NULL]    = { "NULL",          GLUSTERD_MGMT_NULL,     glusterd_null,                         NULL, 0, DRC_NA}, +        [GLUSTERD_PROBE_QUERY]    = { "PROBE_QUERY",   GLUSTERD_PROBE_QUERY,   glusterd_handle_probe_query,           NULL, 0, DRC_NA}, +        [GLUSTERD_FRIEND_ADD]     = { "FRIEND_ADD",    GLUSTERD_FRIEND_ADD,    glusterd_handle_incoming_friend_req,   NULL, 0, DRC_NA}, +        [GLUSTERD_FRIEND_REMOVE]  = { "FRIEND_REMOVE", GLUSTERD_FRIEND_REMOVE, glusterd_handle_incoming_unfriend_req, NULL, 0, DRC_NA}, +        [GLUSTERD_FRIEND_UPDATE]  = { "FRIEND_UPDATE", GLUSTERD_FRIEND_UPDATE, glusterd_handle_friend_update,         NULL, 0, DRC_NA},  };  struct rpcsvc_program gd_svc_peer_prog = { @@ -3889,38 +3889,38 @@ struct rpcsvc_program gd_svc_peer_prog = {  rpcsvc_actor_t gd_svc_cli_actors[] = { -        [GLUSTER_CLI_PROBE]         = { "CLI_PROBE", GLUSTER_CLI_PROBE, glusterd_handle_cli_probe, NULL, 0}, -        [GLUSTER_CLI_CREATE_VOLUME] = { "CLI_CREATE_VOLUME", GLUSTER_CLI_CREATE_VOLUME, glusterd_handle_create_volume, NULL, 0}, -        [GLUSTER_CLI_DEFRAG_VOLUME] = { "CLI_DEFRAG_VOLUME", GLUSTER_CLI_DEFRAG_VOLUME, glusterd_handle_defrag_volume, NULL, 0}, -        [GLUSTER_CLI_DEPROBE]       = { "FRIEND_REMOVE", GLUSTER_CLI_DEPROBE, glusterd_handle_cli_deprobe, NULL, 0}, -        [GLUSTER_CLI_LIST_FRIENDS]  = { "LIST_FRIENDS", GLUSTER_CLI_LIST_FRIENDS, glusterd_handle_cli_list_friends, NULL, 0}, -        [GLUSTER_CLI_UUID_RESET]    = { "UUID_RESET", GLUSTER_CLI_UUID_RESET, glusterd_handle_cli_uuid_reset, NULL, 0}, -        [GLUSTER_CLI_UUID_GET]    = { "UUID_GET", GLUSTER_CLI_UUID_GET, glusterd_handle_cli_uuid_get, NULL, 0}, -        [GLUSTER_CLI_START_VOLUME]  = { "START_VOLUME", GLUSTER_CLI_START_VOLUME, glusterd_handle_cli_start_volume, NULL, 0}, -        [GLUSTER_CLI_STOP_VOLUME]   = { "STOP_VOLUME", GLUSTER_CLI_STOP_VOLUME, glusterd_handle_cli_stop_volume, NULL, 0}, -        [GLUSTER_CLI_DELETE_VOLUME] = { "DELETE_VOLUME", GLUSTER_CLI_DELETE_VOLUME, glusterd_handle_cli_delete_volume, NULL, 0}, -        [GLUSTER_CLI_GET_VOLUME]    = { "GET_VOLUME", GLUSTER_CLI_GET_VOLUME, glusterd_handle_cli_get_volume, NULL, 0}, -        [GLUSTER_CLI_ADD_BRICK]     = { "ADD_BRICK", GLUSTER_CLI_ADD_BRICK, glusterd_handle_add_brick, NULL, 0}, -        [GLUSTER_CLI_REPLACE_BRICK] = { "REPLACE_BRICK", GLUSTER_CLI_REPLACE_BRICK, glusterd_handle_replace_brick, NULL, 0}, -        [GLUSTER_CLI_REMOVE_BRICK]  = { "REMOVE_BRICK", GLUSTER_CLI_REMOVE_BRICK, glusterd_handle_remove_brick, NULL, 0}, -        [GLUSTER_CLI_LOG_ROTATE]    = { "LOG FILENAME", GLUSTER_CLI_LOG_ROTATE, glusterd_handle_log_rotate, NULL, 0}, -        [GLUSTER_CLI_SET_VOLUME]    = { "SET_VOLUME", GLUSTER_CLI_SET_VOLUME, glusterd_handle_set_volume, NULL, 0}, -        [GLUSTER_CLI_SYNC_VOLUME]   = { "SYNC_VOLUME", GLUSTER_CLI_SYNC_VOLUME, glusterd_handle_sync_volume, NULL, 0}, -        [GLUSTER_CLI_RESET_VOLUME]  = { "RESET_VOLUME", GLUSTER_CLI_RESET_VOLUME, glusterd_handle_reset_volume, NULL, 0}, -        [GLUSTER_CLI_FSM_LOG]       = { "FSM_LOG", GLUSTER_CLI_FSM_LOG, glusterd_handle_fsm_log, NULL, 0}, -        [GLUSTER_CLI_GSYNC_SET]     = { "GSYNC_SET", GLUSTER_CLI_GSYNC_SET, glusterd_handle_gsync_set, NULL, 0}, -        [GLUSTER_CLI_PROFILE_VOLUME] = { "STATS_VOLUME", GLUSTER_CLI_PROFILE_VOLUME, glusterd_handle_cli_profile_volume, NULL, 0}, -        [GLUSTER_CLI_QUOTA]         = { "QUOTA", GLUSTER_CLI_QUOTA, glusterd_handle_quota, NULL, 0}, -        [GLUSTER_CLI_GETWD]         = { "GETWD", GLUSTER_CLI_GETWD, glusterd_handle_getwd, NULL, 1}, -        [GLUSTER_CLI_STATUS_VOLUME]  = {"STATUS_VOLUME", GLUSTER_CLI_STATUS_VOLUME, glusterd_handle_status_volume, NULL, 0}, -        [GLUSTER_CLI_MOUNT]         = { "MOUNT", GLUSTER_CLI_MOUNT, glusterd_handle_mount, NULL, 1}, -        [GLUSTER_CLI_UMOUNT]        = { "UMOUNT", GLUSTER_CLI_UMOUNT, glusterd_handle_umount, NULL, 1}, -        [GLUSTER_CLI_HEAL_VOLUME]  = { "HEAL_VOLUME", GLUSTER_CLI_HEAL_VOLUME, glusterd_handle_cli_heal_volume, NULL, 0}, -        [GLUSTER_CLI_STATEDUMP_VOLUME] = {"STATEDUMP_VOLUME", GLUSTER_CLI_STATEDUMP_VOLUME, glusterd_handle_cli_statedump_volume, NULL, 0}, -        [GLUSTER_CLI_LIST_VOLUME] = {"LIST_VOLUME", GLUSTER_CLI_LIST_VOLUME, glusterd_handle_cli_list_volume, NULL, 0}, -        [GLUSTER_CLI_CLRLOCKS_VOLUME] = {"CLEARLOCKS_VOLUME", GLUSTER_CLI_CLRLOCKS_VOLUME, glusterd_handle_cli_clearlocks_volume, NULL, 0}, +        [GLUSTER_CLI_PROBE]              = { "CLI_PROBE",         GLUSTER_CLI_PROBE,            glusterd_handle_cli_probe,             NULL, 0, DRC_NA}, +        [GLUSTER_CLI_CREATE_VOLUME]      = { "CLI_CREATE_VOLUME", GLUSTER_CLI_CREATE_VOLUME,    glusterd_handle_create_volume,         NULL, 0, DRC_NA}, +        [GLUSTER_CLI_DEFRAG_VOLUME]      = { "CLI_DEFRAG_VOLUME", GLUSTER_CLI_DEFRAG_VOLUME,    glusterd_handle_defrag_volume,         NULL, 0, DRC_NA}, +        [GLUSTER_CLI_DEPROBE]            = { "FRIEND_REMOVE",     GLUSTER_CLI_DEPROBE,          glusterd_handle_cli_deprobe,           NULL, 0, DRC_NA}, +        [GLUSTER_CLI_LIST_FRIENDS]       = { "LIST_FRIENDS",      GLUSTER_CLI_LIST_FRIENDS,     glusterd_handle_cli_list_friends,      NULL, 0, DRC_NA}, +        [GLUSTER_CLI_UUID_RESET]         = { "UUID_RESET",        GLUSTER_CLI_UUID_RESET,       glusterd_handle_cli_uuid_reset,        NULL, 0, DRC_NA}, +        [GLUSTER_CLI_UUID_GET]           = { "UUID_GET",          GLUSTER_CLI_UUID_GET,         glusterd_handle_cli_uuid_get,          NULL, 0, DRC_NA}, +        [GLUSTER_CLI_START_VOLUME]       = { "START_VOLUME",      GLUSTER_CLI_START_VOLUME,     glusterd_handle_cli_start_volume,      NULL, 0, DRC_NA}, +        [GLUSTER_CLI_STOP_VOLUME]        = { "STOP_VOLUME",       GLUSTER_CLI_STOP_VOLUME,      glusterd_handle_cli_stop_volume,       NULL, 0, DRC_NA}, +        [GLUSTER_CLI_DELETE_VOLUME]      = { "DELETE_VOLUME",     GLUSTER_CLI_DELETE_VOLUME,    glusterd_handle_cli_delete_volume,     NULL, 0, DRC_NA}, +        [GLUSTER_CLI_GET_VOLUME]         = { "GET_VOLUME",        GLUSTER_CLI_GET_VOLUME,       glusterd_handle_cli_get_volume,        NULL, 0, DRC_NA}, +        [GLUSTER_CLI_ADD_BRICK]          = { "ADD_BRICK",         GLUSTER_CLI_ADD_BRICK,        glusterd_handle_add_brick,             NULL, 0, DRC_NA}, +        [GLUSTER_CLI_REPLACE_BRICK]      = { "REPLACE_BRICK",     GLUSTER_CLI_REPLACE_BRICK,    glusterd_handle_replace_brick,         NULL, 0, DRC_NA}, +        [GLUSTER_CLI_REMOVE_BRICK]       = { "REMOVE_BRICK",      GLUSTER_CLI_REMOVE_BRICK,     glusterd_handle_remove_brick,          NULL, 0, DRC_NA}, +        [GLUSTER_CLI_LOG_ROTATE]         = { "LOG FILENAME",      GLUSTER_CLI_LOG_ROTATE,       glusterd_handle_log_rotate,            NULL, 0, DRC_NA}, +        [GLUSTER_CLI_SET_VOLUME]         = { "SET_VOLUME",        GLUSTER_CLI_SET_VOLUME,       glusterd_handle_set_volume,            NULL, 0, DRC_NA}, +        [GLUSTER_CLI_SYNC_VOLUME]        = { "SYNC_VOLUME",       GLUSTER_CLI_SYNC_VOLUME,      glusterd_handle_sync_volume,           NULL, 0, DRC_NA}, +        [GLUSTER_CLI_RESET_VOLUME]       = { "RESET_VOLUME",      GLUSTER_CLI_RESET_VOLUME,     glusterd_handle_reset_volume,          NULL, 0, DRC_NA}, +        [GLUSTER_CLI_FSM_LOG]            = { "FSM_LOG",           GLUSTER_CLI_FSM_LOG,          glusterd_handle_fsm_log,               NULL, 0, DRC_NA}, +        [GLUSTER_CLI_GSYNC_SET]          = { "GSYNC_SET",         GLUSTER_CLI_GSYNC_SET,        glusterd_handle_gsync_set,             NULL, 0, DRC_NA}, +        [GLUSTER_CLI_PROFILE_VOLUME]     = { "STATS_VOLUME",      GLUSTER_CLI_PROFILE_VOLUME,   glusterd_handle_cli_profile_volume,    NULL, 0, DRC_NA}, +        [GLUSTER_CLI_QUOTA]              = { "QUOTA",             GLUSTER_CLI_QUOTA,            glusterd_handle_quota,                 NULL, 0, DRC_NA}, +        [GLUSTER_CLI_GETWD]              = { "GETWD",             GLUSTER_CLI_GETWD,            glusterd_handle_getwd,                 NULL, 1, DRC_NA}, +        [GLUSTER_CLI_STATUS_VOLUME]      = {"STATUS_VOLUME",      GLUSTER_CLI_STATUS_VOLUME,    glusterd_handle_status_volume,         NULL, 0, DRC_NA}, +        [GLUSTER_CLI_MOUNT]              = { "MOUNT",             GLUSTER_CLI_MOUNT,            glusterd_handle_mount,                 NULL, 1, DRC_NA}, +        [GLUSTER_CLI_UMOUNT]             = { "UMOUNT",            GLUSTER_CLI_UMOUNT,           glusterd_handle_umount,                NULL, 1, DRC_NA}, +        [GLUSTER_CLI_HEAL_VOLUME]        = { "HEAL_VOLUME",       GLUSTER_CLI_HEAL_VOLUME,      glusterd_handle_cli_heal_volume,       NULL, 0, DRC_NA}, +        [GLUSTER_CLI_STATEDUMP_VOLUME]   = {"STATEDUMP_VOLUME",   GLUSTER_CLI_STATEDUMP_VOLUME, glusterd_handle_cli_statedump_volume,  NULL, 0, DRC_NA}, +        [GLUSTER_CLI_LIST_VOLUME]        = {"LIST_VOLUME",        GLUSTER_CLI_LIST_VOLUME,      glusterd_handle_cli_list_volume,       NULL, 0, DRC_NA}, +        [GLUSTER_CLI_CLRLOCKS_VOLUME]    = {"CLEARLOCKS_VOLUME",  GLUSTER_CLI_CLRLOCKS_VOLUME,  glusterd_handle_cli_clearlocks_volume, NULL, 0, DRC_NA},  #ifdef HAVE_BD_XLATOR -        [GLUSTER_CLI_BD_OP]       = {"BD_OP", GLUSTER_CLI_BD_OP, glusterd_handle_cli_bd_op, NULL, 0}, +        [GLUSTER_CLI_BD_OP]              = {"BD_OP",              GLUSTER_CLI_BD_OP,            glusterd_handle_cli_bd_op,             NULL, 0, DRC_NA},  #endif  }; diff --git a/xlators/mgmt/glusterd/src/glusterd-handshake.c b/xlators/mgmt/glusterd/src/glusterd-handshake.c index 05c3012e419..c5a018ec41b 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handshake.c +++ b/xlators/mgmt/glusterd/src/glusterd-handshake.c @@ -582,11 +582,9 @@ glusterd_mgmt_hndsk_versions_ack (rpcsvc_request_t *req)  }  rpcsvc_actor_t gluster_handshake_actors[] = { -        [GF_HNDSK_NULL]         = {"NULL", GF_HNDSK_NULL, NULL, NULL, 0}, -        [GF_HNDSK_GETSPEC]      = {"GETSPEC", GF_HNDSK_GETSPEC, -                                   server_getspec, NULL, 0}, -        [GF_HNDSK_EVENT_NOTIFY] = {"EVENTNOTIFY", GF_HNDSK_EVENT_NOTIFY, -                                   server_event_notify,  NULL, 0}, +        [GF_HNDSK_NULL]         = {"NULL",        GF_HNDSK_NULL,         NULL,                NULL, 0, DRC_NA}, +        [GF_HNDSK_GETSPEC]      = {"GETSPEC",     GF_HNDSK_GETSPEC,      server_getspec,      NULL, 0, DRC_NA}, +        [GF_HNDSK_EVENT_NOTIFY] = {"EVENTNOTIFY", GF_HNDSK_EVENT_NOTIFY, server_event_notify, NULL, 0, DRC_NA},  }; diff --git a/xlators/mgmt/glusterd/src/glusterd-pmap.c b/xlators/mgmt/glusterd/src/glusterd-pmap.c index aab6744a418..9fdd782fe9e 100644 --- a/xlators/mgmt/glusterd/src/glusterd-pmap.c +++ b/xlators/mgmt/glusterd/src/glusterd-pmap.c @@ -474,17 +474,12 @@ gluster_pmap_signout (rpcsvc_request_t *req)  }  rpcsvc_actor_t gluster_pmap_actors[] = { -        [GF_PMAP_NULL] = {"NULL", GF_PMAP_NULL, NULL, NULL, 0}, -        [GF_PMAP_PORTBYBRICK] = {"PORTBYBRICK", GF_PMAP_PORTBYBRICK, -                                 gluster_pmap_portbybrick, NULL, 0}, -        [GF_PMAP_BRICKBYPORT] = {"BRICKBYPORT", GF_PMAP_BRICKBYPORT, -                                 gluster_pmap_brickbyport, NULL, 0}, -        [GF_PMAP_SIGNIN] = {"SIGNIN", GF_PMAP_SIGNIN, -                              gluster_pmap_signin, NULL, 0}, -        [GF_PMAP_SIGNOUT] = {"SIGNOUT", GF_PMAP_SIGNOUT, -                              gluster_pmap_signout, NULL, 0}, -        [GF_PMAP_SIGNUP] = {"SIGNUP", GF_PMAP_SIGNUP, -                              gluster_pmap_signup, NULL, 0}, +        [GF_PMAP_NULL]        = {"NULL",        GF_PMAP_NULL,        NULL,                     NULL, 0, DRC_NA}, +        [GF_PMAP_PORTBYBRICK] = {"PORTBYBRICK", GF_PMAP_PORTBYBRICK, gluster_pmap_portbybrick, NULL, 0, DRC_NA}, +        [GF_PMAP_BRICKBYPORT] = {"BRICKBYPORT", GF_PMAP_BRICKBYPORT, gluster_pmap_brickbyport, NULL, 0, DRC_NA}, +        [GF_PMAP_SIGNIN]      = {"SIGNIN",      GF_PMAP_SIGNIN,      gluster_pmap_signin,      NULL, 0, DRC_NA}, +        [GF_PMAP_SIGNOUT]     = {"SIGNOUT",     GF_PMAP_SIGNOUT,     gluster_pmap_signout,     NULL, 0, DRC_NA}, +        [GF_PMAP_SIGNUP]      = {"SIGNUP",      GF_PMAP_SIGNUP,      gluster_pmap_signup,      NULL, 0, DRC_NA},  }; diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index 73f966c9745..4162274e005 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -2882,6 +2882,10 @@ build_nfs_graph (volgen_graph_t *graph, dict_t *mod_dict)          if (ret)                  goto out; +        ret = xlator_set_option (nfsxl, "nfs.drc", "on"); +        if (ret) +                goto out; +          list_for_each_entry (voliter, &priv->volumes, vol_list) {                  if (voliter->status != GLUSTERD_STATUS_STARTED)                          continue; diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c index f112ccfc298..6c4af6e3e61 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c @@ -1164,6 +1164,18 @@ struct volopt_map_entry glusterd_volopt_map[] = {            .type        = NO_DOC,            .op_version  = 2          }, +        { .key         = "nfs.drc", +          .voltype     = "nfs/server", +          .option      = "nfs.drc", +          .type        = GLOBAL_DOC, +          .op_version  = 1 +        }, +        { .key         = "nfs.drc-size", +          .voltype     = "nfs/server", +          .option      = "nfs.drc-size", +          .type        = GLOBAL_DOC, +          .op_version  = 1 +        },          /* Other options which don't fit any place above */          { .key        = "features.read-only", diff --git a/xlators/nfs/server/src/mount3.c b/xlators/nfs/server/src/mount3.c index f2b977eea1f..983cbff027d 100644 --- a/xlators/nfs/server/src/mount3.c +++ b/xlators/nfs/server/src/mount3.c @@ -1843,12 +1843,12 @@ out:  }  rpcsvc_actor_t  mnt3svc_actors[MOUNT3_PROC_COUNT] = { -        {"NULL", MOUNT3_NULL, mnt3svc_null, NULL, 0}, -        {"MNT", MOUNT3_MNT, mnt3svc_mnt, NULL, 0}, -        {"DUMP", MOUNT3_DUMP, mnt3svc_dump, NULL, 0}, -        {"UMNT", MOUNT3_UMNT, mnt3svc_umnt, NULL, 0}, -        {"UMNTALL", MOUNT3_UMNTALL, mnt3svc_umntall, NULL, 0}, -        {"EXPORT", MOUNT3_EXPORT, mnt3svc_export, NULL, 0} +        {"NULL",    MOUNT3_NULL,    mnt3svc_null,    NULL, 0, DRC_NA}, +        {"MNT",     MOUNT3_MNT,     mnt3svc_mnt,     NULL, 0, DRC_NA}, +        {"DUMP",    MOUNT3_DUMP,    mnt3svc_dump,    NULL, 0, DRC_NA}, +        {"UMNT",    MOUNT3_UMNT,    mnt3svc_umnt,    NULL, 0, DRC_NA}, +        {"UMNTALL", MOUNT3_UMNTALL, mnt3svc_umntall, NULL, 0, DRC_NA}, +        {"EXPORT",  MOUNT3_EXPORT,  mnt3svc_export,  NULL, 0, DRC_NA}  }; @@ -1939,12 +1939,12 @@ err:  rpcsvc_actor_t  mnt1svc_actors[MOUNT1_PROC_COUNT] = { -        {"NULL", MOUNT1_NULL, mnt3svc_null, NULL, 0}, -        {{0, 0}, }, -        {"DUMP", MOUNT1_DUMP, mnt3svc_dump, NULL, 0}, -        {"UMNT", MOUNT1_UMNT, mnt3svc_umnt, NULL, 0}, -        {{0, 0}, }, -        {"EXPORT", MOUNT1_EXPORT, mnt3svc_export, NULL, 0} +        {"NULL",    MOUNT1_NULL,    mnt3svc_null,   NULL, 0, DRC_NA}, +        {"MNT",     MOUNT1_MNT,     NULL,           NULL, 0, DRC_NA }, +        {"DUMP",    MOUNT1_DUMP,    mnt3svc_dump,   NULL, 0, DRC_NA}, +        {"UMNT",    MOUNT1_UMNT,    mnt3svc_umnt,   NULL, 0, DRC_NA}, +        {"UMNTALL", MOUNT1_UMNTALL, NULL,           NULL, 0, DRC_NA}, +        {"EXPORT",  MOUNT1_EXPORT,  mnt3svc_export, NULL, 0, DRC_NA}  };  rpcsvc_program_t        mnt1prog = { diff --git a/xlators/nfs/server/src/nfs.c b/xlators/nfs/server/src/nfs.c index 7b36d59e82a..6cd0594e691 100644 --- a/xlators/nfs/server/src/nfs.c +++ b/xlators/nfs/server/src/nfs.c @@ -43,6 +43,7 @@  #include "nlm4.h"  #include "options.h"  #include "acl3.h" +#include "rpc-drc.h"  #define STRINGIFY(val) #val  #define TOSTRING(val) STRINGIFY(val) @@ -798,6 +799,21 @@ free_rpcsvc:          return nfs;  } +int +nfs_drc_init (xlator_t *this) +{ +        int       ret     = -1; +        rpcsvc_t *svc     = NULL; + +        svc = ((struct nfs_state *)(this->private))->rpcsvc; +        if (!svc) +                goto out; + +        ret = rpcsvc_drc_init (svc, this->options); + + out: +        return ret; +}  int  init (xlator_t *this) { @@ -853,7 +869,9 @@ init (xlator_t *this) {                  goto err;          } -        gf_log (GF_NFS, GF_LOG_INFO, "NFS service started"); +        ret = nfs_drc_init (this); +        if (ret == 0) +                gf_log (GF_NFS, GF_LOG_INFO, "NFS service started");  err:          return ret; @@ -1008,7 +1026,22 @@ nlm_priv (xlator_t *this);  int32_t  nfs_priv (xlator_t *this)  { -        return nlm_priv (this); +        int32_t ret = -1; + +        /* DRC needs the global drc structure, xl is of no use to it. */ +        ret = rpcsvc_drc_priv (((struct nfs_state *)(this->private))->rpcsvc->drc); +        if (ret) { +                gf_log (this->name, GF_LOG_DEBUG, "Statedump of DRC failed"); +                goto out; +        } + +        ret = nlm_priv (this); +        if (ret) { +                gf_log (this->name, GF_LOG_DEBUG, "Statedump of NLM failed"); +                goto out; +        } + out: +        return ret;  } @@ -1314,6 +1347,18 @@ struct volume_options options[] = {            .default_value = "on",            .description = "This option is used to control ACL support for NFS."          }, +        { .key  = {"nfs.drc"}, +          .type = GF_OPTION_TYPE_STR, +          .default_value = "off", +          .description = "Enable Duplicate Request Cache in gNfs server to " +                         "improve correctness of non-idempotent operations like " +                         "write, delete, link, et al" +        }, +        { .key  = {"nfs.drc-size"}, +          .type = GF_OPTION_TYPE_INT, +          .default_value = "0x20000", +          .description = "Sets the number of non-idempotent " +                         "requests to cache in drc" +        },          { .key  = {NULL} },  }; - diff --git a/xlators/nfs/server/src/nfs3.c b/xlators/nfs/server/src/nfs3.c index 308b28924c7..4e641228724 100644 --- a/xlators/nfs/server/src/nfs3.c +++ b/xlators/nfs/server/src/nfs3.c @@ -5108,28 +5108,28 @@ rpcerr:  rpcsvc_actor_t          nfs3svc_actors[NFS3_PROC_COUNT] = { -        {"NULL",        NFS3_NULL,      nfs3svc_null,   NULL,   0}, -        {"GETATTR",     NFS3_GETATTR,   nfs3svc_getattr,NULL,   0}, -        {"SETATTR",     NFS3_SETATTR,   nfs3svc_setattr,NULL,   0}, -        {"LOOKUP",      NFS3_LOOKUP,    nfs3svc_lookup, NULL,   0}, -        {"ACCESS",      NFS3_ACCESS,    nfs3svc_access, NULL,   0}, -        {"READLINK",    NFS3_READLINK,  nfs3svc_readlink,NULL,  0}, -        {"READ",        NFS3_READ,      nfs3svc_read,   NULL,   0}, -        {"WRITE",       NFS3_WRITE,     nfs3svc_write, nfs3svc_write_vecsizer, 0}, -        {"CREATE",      NFS3_CREATE,    nfs3svc_create, NULL,   0}, -        {"MKDIR",       NFS3_MKDIR,     nfs3svc_mkdir,  NULL,   0}, -        {"SYMLINK",     NFS3_SYMLINK,   nfs3svc_symlink,NULL,   0}, -        {"MKNOD",       NFS3_MKNOD,     nfs3svc_mknod,  NULL,   0}, -        {"REMOVE",      NFS3_REMOVE,    nfs3svc_remove, NULL,   0}, -        {"RMDIR",       NFS3_RMDIR,     nfs3svc_rmdir,  NULL,   0}, -        {"RENAME",      NFS3_RENAME,    nfs3svc_rename, NULL,   0}, -        {"LINK",        NFS3_LINK,      nfs3svc_link,   NULL,   0}, -        {"READDIR",     NFS3_READDIR,   nfs3svc_readdir,NULL,   0}, -        {"READDIRPLUS", NFS3_READDIRP,  nfs3svc_readdirp,NULL,  0}, -        {"FSSTAT",      NFS3_FSSTAT,    nfs3svc_fsstat, NULL,   0}, -        {"FSINFO",      NFS3_FSINFO,    nfs3svc_fsinfo, NULL,   0}, -        {"PATHCONF",    NFS3_PATHCONF,  nfs3svc_pathconf,NULL,  0}, -        {"COMMIT",      NFS3_COMMIT,    nfs3svc_commit, NULL,   0} +        {"NULL",        NFS3_NULL,      nfs3svc_null,      NULL,   0, DRC_IDEMPOTENT}, +        {"GETATTR",     NFS3_GETATTR,   nfs3svc_getattr,   NULL,   0, DRC_IDEMPOTENT}, +        {"SETATTR",     NFS3_SETATTR,   nfs3svc_setattr,   NULL,   0, DRC_NON_IDEMPOTENT}, +        {"LOOKUP",      NFS3_LOOKUP,    nfs3svc_lookup,    NULL,   0, DRC_IDEMPOTENT}, +        {"ACCESS",      NFS3_ACCESS,    nfs3svc_access,    NULL,   0, DRC_IDEMPOTENT}, +        {"READLINK",    NFS3_READLINK,  nfs3svc_readlink,  NULL,   0, DRC_IDEMPOTENT}, +        {"READ",        NFS3_READ,      nfs3svc_read,      NULL,   0, DRC_IDEMPOTENT}, +        {"WRITE",       NFS3_WRITE,     nfs3svc_write,     nfs3svc_write_vecsizer, 0, DRC_NON_IDEMPOTENT}, +        {"CREATE",      NFS3_CREATE,    nfs3svc_create,    NULL,   0, DRC_NON_IDEMPOTENT}, +        {"MKDIR",       NFS3_MKDIR,     nfs3svc_mkdir,     NULL,   0, DRC_NON_IDEMPOTENT}, +        {"SYMLINK",     NFS3_SYMLINK,   nfs3svc_symlink,   NULL,   0, DRC_NON_IDEMPOTENT}, +        {"MKNOD",       NFS3_MKNOD,     nfs3svc_mknod,     NULL,   0, DRC_NON_IDEMPOTENT}, +        {"REMOVE",      NFS3_REMOVE,    nfs3svc_remove,    NULL,   0, DRC_NON_IDEMPOTENT}, +        {"RMDIR",       NFS3_RMDIR,     nfs3svc_rmdir,     NULL,   0, DRC_NON_IDEMPOTENT}, +        {"RENAME",      NFS3_RENAME,    nfs3svc_rename,    NULL,   0, DRC_NON_IDEMPOTENT}, +        {"LINK",        NFS3_LINK,      nfs3svc_link,      NULL,   0, DRC_NON_IDEMPOTENT}, +        {"READDIR",     NFS3_READDIR,   nfs3svc_readdir,   NULL,   0, DRC_IDEMPOTENT}, +        {"READDIRPLUS", NFS3_READDIRP,  nfs3svc_readdirp,  NULL,   0, DRC_IDEMPOTENT}, +        {"FSSTAT",      NFS3_FSSTAT,    nfs3svc_fsstat,    NULL,   0, DRC_IDEMPOTENT}, +        {"FSINFO",      NFS3_FSINFO,    nfs3svc_fsinfo,    NULL,   0, DRC_IDEMPOTENT}, +        {"PATHCONF",    NFS3_PATHCONF,  nfs3svc_pathconf,  NULL,   0, DRC_IDEMPOTENT}, +        {"COMMIT",      NFS3_COMMIT,    nfs3svc_commit,    NULL,   0, DRC_IDEMPOTENT}  }; diff --git a/xlators/nfs/server/src/nlm4.c b/xlators/nfs/server/src/nlm4.c index 595738b2c17..041e4317acc 100644 --- a/xlators/nfs/server/src/nlm4.c +++ b/xlators/nfs/server/src/nlm4.c @@ -2286,34 +2286,34 @@ nlm4svc_sm_notify (struct nlm_sm_status *status)  rpcsvc_actor_t  nlm4svc_actors[NLM4_PROC_COUNT] = {          /* 0 */ -        {"NULL",       NLM4_NULL,         nlm4svc_null,      NULL}, -        {"TEST",       NLM4_TEST,         nlm4svc_test,      NULL}, -        {"LOCK",       NLM4_LOCK,         nlm4svc_lock,      NULL}, -        {"CANCEL",     NLM4_CANCEL,       nlm4svc_cancel,    NULL}, -        {"UNLOCK",     NLM4_UNLOCK,       nlm4svc_unlock,    NULL}, +        {"NULL",       NLM4_NULL,         nlm4svc_null,      NULL, 0, DRC_IDEMPOTENT}, +        {"TEST",       NLM4_TEST,         nlm4svc_test,      NULL, 0, DRC_IDEMPOTENT}, +        {"LOCK",       NLM4_LOCK,         nlm4svc_lock,      NULL, 0, DRC_NON_IDEMPOTENT}, +        {"CANCEL",     NLM4_CANCEL,       nlm4svc_cancel,    NULL, 0, DRC_NON_IDEMPOTENT}, +        {"UNLOCK",     NLM4_UNLOCK,       nlm4svc_unlock,    NULL, 0, DRC_NON_IDEMPOTENT},          /* 5 */ -        {"GRANTED",    NLM4_GRANTED,      NULL,              NULL}, -        {"TEST",       NLM4_TEST_MSG,     NULL,              NULL}, -        {"LOCK",       NLM4_LOCK_MSG,     NULL,              NULL}, -        {"CANCEL",     NLM4_CANCEL_MSG,   NULL,              NULL}, -        {"UNLOCK",     NLM4_UNLOCK_MSG,   NULL,              NULL}, +        {"GRANTED",    NLM4_GRANTED,      NULL,              NULL, 0, DRC_NA}, +        {"TEST",       NLM4_TEST_MSG,     NULL,              NULL, 0, DRC_NA}, +        {"LOCK",       NLM4_LOCK_MSG,     NULL,              NULL, 0, DRC_NA}, +        {"CANCEL",     NLM4_CANCEL_MSG,   NULL,              NULL, 0, DRC_NA}, +        {"UNLOCK",     NLM4_UNLOCK_MSG,   NULL,              NULL, 0, DRC_NA},          /* 10 */ -        {"GRANTED",    NLM4_GRANTED_MSG,  NULL,              NULL}, -        {"TEST",       NLM4_TEST_RES,     NULL,              NULL}, -        {"LOCK",       NLM4_LOCK_RES,     NULL,              NULL}, -        {"CANCEL",     NLM4_CANCEL_RES,   NULL,              NULL}, -        {"UNLOCK",     NLM4_UNLOCK_RES,   NULL,              NULL}, +        {"GRANTED",    NLM4_GRANTED_MSG,  NULL,              NULL, 0, DRC_NA}, +        {"TEST",       NLM4_TEST_RES,     NULL,              NULL, 0, DRC_NA}, +        {"LOCK",       NLM4_LOCK_RES,     NULL,              NULL, 0, DRC_NA}, +        {"CANCEL",     NLM4_CANCEL_RES,   NULL,              NULL, 0, DRC_NA}, +        {"UNLOCK",     NLM4_UNLOCK_RES,   NULL,              NULL, 0, DRC_NA},          /* 15 ; procedures 17,18,19 are not defined by nlm */ -        {"GRANTED",    NLM4_GRANTED_RES,  NULL,              NULL}, -        {"SM_NOTIFY",  NLM4_SM_NOTIFY,    NULL,              NULL}, -        {"SEVENTEEN",  NLM4_SEVENTEEN,    NULL,              NULL}, -        {"EIGHTEEN",   NLM4_EIGHTEEN,     NULL,              NULL}, -        {"NINETEEN",   NLM4_NINETEEN,     NULL,              NULL}, +        {"GRANTED",    NLM4_GRANTED_RES,  NULL,              NULL, 0, DRC_NA}, +        {"SM_NOTIFY",  NLM4_SM_NOTIFY,    NULL,              NULL, 0, DRC_NA}, +        {"SEVENTEEN",  NLM4_SEVENTEEN,    NULL,              NULL, 0, DRC_NA}, +        {"EIGHTEEN",   NLM4_EIGHTEEN,     NULL,              NULL, 0, DRC_NA}, +        {"NINETEEN",   NLM4_NINETEEN,     NULL,              NULL, 0, DRC_NA},          /* 20 */ -        {"SHARE",      NLM4_SHARE,        nlm4svc_share,     NULL}, -        {"UNSHARE",    NLM4_UNSHARE,      nlm4svc_unshare,   NULL}, -        {"NM_LOCK",    NLM4_NM_LOCK,      nlm4svc_nm_lock,   NULL}, -        {"FREE_ALL",   NLM4_FREE_ALL,     nlm4svc_free_all,  NULL}, +        {"SHARE",      NLM4_SHARE,        nlm4svc_share,     NULL, 0, DRC_NON_IDEMPOTENT}, +        {"UNSHARE",    NLM4_UNSHARE,      nlm4svc_unshare,   NULL, 0, DRC_NON_IDEMPOTENT}, +        {"NM_LOCK",    NLM4_NM_LOCK,      nlm4svc_nm_lock,   NULL, 0, DRC_NON_IDEMPOTENT}, +        {"FREE_ALL",   NLM4_FREE_ALL,     nlm4svc_free_all,  NULL, 0, DRC_IDEMPOTENT},  };  rpcsvc_program_t        nlm4prog = { diff --git a/xlators/protocol/server/src/server-handshake.c b/xlators/protocol/server/src/server-handshake.c index ed3d75860e3..8886221aa92 100644 --- a/xlators/protocol/server/src/server-handshake.c +++ b/xlators/protocol/server/src/server-handshake.c @@ -749,11 +749,11 @@ fail:  }  rpcsvc_actor_t gluster_handshake_actors[] = { -        [GF_HNDSK_NULL]       = {"NULL",      GF_HNDSK_NULL,      server_null, NULL, 0}, -        [GF_HNDSK_SETVOLUME]  = {"SETVOLUME", GF_HNDSK_SETVOLUME, server_setvolume, NULL, 0}, -        [GF_HNDSK_GETSPEC]    = {"GETSPEC",   GF_HNDSK_GETSPEC,   server_getspec, NULL, 0}, -        [GF_HNDSK_PING]       = {"PING",      GF_HNDSK_PING,      server_ping, NULL, 0}, -        [GF_HNDSK_SET_LK_VER] = {"SET_LK_VER", GF_HNDSK_SET_LK_VER, server_set_lk_version, NULL, 0}, +        [GF_HNDSK_NULL]       = {"NULL",       GF_HNDSK_NULL,       server_null,           NULL, 0, DRC_NA}, +        [GF_HNDSK_SETVOLUME]  = {"SETVOLUME",  GF_HNDSK_SETVOLUME,  server_setvolume,      NULL, 0, DRC_NA}, +        [GF_HNDSK_GETSPEC]    = {"GETSPEC",    GF_HNDSK_GETSPEC,    server_getspec,        NULL, 0, DRC_NA}, +        [GF_HNDSK_PING]       = {"PING",       GF_HNDSK_PING,       server_ping,           NULL, 0, DRC_NA}, +        [GF_HNDSK_SET_LK_VER] = {"SET_LK_VER", GF_HNDSK_SET_LK_VER, server_set_lk_version, NULL, 0, DRC_NA},  }; diff --git a/xlators/protocol/server/src/server-helpers.c b/xlators/protocol/server/src/server-helpers.c index 246a5ec6c5f..c8d42505603 100644 --- a/xlators/protocol/server/src/server-helpers.c +++ b/xlators/protocol/server/src/server-helpers.c @@ -809,7 +809,6 @@ get_frame_from_request (rpcsvc_request_t *req)                  goto out;          frame->root->op       = req->procnum; -        frame->root->type     = req->type;          frame->root->unique   = req->xid; diff --git a/xlators/protocol/server/src/server-rpc-fops.c b/xlators/protocol/server/src/server-rpc-fops.c index 1dcfc789015..25d9f17b5ac 100644 --- a/xlators/protocol/server/src/server-rpc-fops.c +++ b/xlators/protocol/server/src/server-rpc-fops.c @@ -6024,52 +6024,52 @@ out:  rpcsvc_actor_t glusterfs3_3_fop_actors[] = { -        [GFS3_OP_NULL]        = { "NULL",       GFS3_OP_NULL, server_null, NULL, 0}, -        [GFS3_OP_STAT]        = { "STAT",       GFS3_OP_STAT, server3_3_stat, NULL, 0}, -        [GFS3_OP_READLINK]    = { "READLINK",   GFS3_OP_READLINK, server3_3_readlink, NULL, 0}, -        [GFS3_OP_MKNOD]       = { "MKNOD",      GFS3_OP_MKNOD, server3_3_mknod, NULL, 0}, -        [GFS3_OP_MKDIR]       = { "MKDIR",      GFS3_OP_MKDIR, server3_3_mkdir, NULL, 0}, -        [GFS3_OP_UNLINK]      = { "UNLINK",     GFS3_OP_UNLINK, server3_3_unlink, NULL, 0}, -        [GFS3_OP_RMDIR]       = { "RMDIR",      GFS3_OP_RMDIR, server3_3_rmdir, NULL, 0}, -        [GFS3_OP_SYMLINK]     = { "SYMLINK",    GFS3_OP_SYMLINK, server3_3_symlink, NULL, 0}, -        [GFS3_OP_RENAME]      = { "RENAME",     GFS3_OP_RENAME, server3_3_rename, NULL, 0}, -        [GFS3_OP_LINK]        = { "LINK",       GFS3_OP_LINK, server3_3_link, NULL, 0}, -        [GFS3_OP_TRUNCATE]    = { "TRUNCATE",   GFS3_OP_TRUNCATE, server3_3_truncate, NULL, 0}, -        [GFS3_OP_OPEN]        = { "OPEN",       GFS3_OP_OPEN, server3_3_open, NULL, 0}, -        [GFS3_OP_READ]        = { "READ",       GFS3_OP_READ, server3_3_readv, NULL, 0}, -        [GFS3_OP_WRITE]       = { "WRITE",      GFS3_OP_WRITE, server3_3_writev, server3_3_writev_vecsizer, 0}, -        [GFS3_OP_STATFS]      = { "STATFS",     GFS3_OP_STATFS, server3_3_statfs, NULL, 0}, -        [GFS3_OP_FLUSH]       = { "FLUSH",      GFS3_OP_FLUSH, server3_3_flush, NULL, 0}, -        [GFS3_OP_FSYNC]       = { "FSYNC",      GFS3_OP_FSYNC, server3_3_fsync, NULL, 0}, -        [GFS3_OP_SETXATTR]    = { "SETXATTR",   GFS3_OP_SETXATTR, server3_3_setxattr, NULL, 0}, -        [GFS3_OP_GETXATTR]    = { "GETXATTR",   GFS3_OP_GETXATTR, server3_3_getxattr, NULL, 0}, -        [GFS3_OP_REMOVEXATTR] = { "REMOVEXATTR", GFS3_OP_REMOVEXATTR, server3_3_removexattr, NULL, 0}, -        [GFS3_OP_OPENDIR]     = { "OPENDIR",    GFS3_OP_OPENDIR, server3_3_opendir, NULL, 0}, -        [GFS3_OP_FSYNCDIR]    = { "FSYNCDIR",   GFS3_OP_FSYNCDIR, server3_3_fsyncdir, NULL, 0}, -        [GFS3_OP_ACCESS]      = { "ACCESS",     GFS3_OP_ACCESS, server3_3_access, NULL, 0}, -        [GFS3_OP_CREATE]      = { "CREATE",     GFS3_OP_CREATE, server3_3_create, NULL, 0}, -        [GFS3_OP_FTRUNCATE]   = { "FTRUNCATE",  GFS3_OP_FTRUNCATE, server3_3_ftruncate, NULL, 0}, -        [GFS3_OP_FSTAT]       = { "FSTAT",      GFS3_OP_FSTAT, server3_3_fstat, NULL, 0}, -        [GFS3_OP_LK]          = { "LK",         GFS3_OP_LK, server3_3_lk, NULL, 0}, -        [GFS3_OP_LOOKUP]      = { "LOOKUP",     GFS3_OP_LOOKUP, server3_3_lookup, NULL, 0}, -        [GFS3_OP_READDIR]     = { "READDIR",    GFS3_OP_READDIR, server3_3_readdir, NULL, 0}, -        [GFS3_OP_INODELK]     = { "INODELK",    GFS3_OP_INODELK, server3_3_inodelk, NULL, 0}, -        [GFS3_OP_FINODELK]    = { "FINODELK",   GFS3_OP_FINODELK, server3_3_finodelk, NULL, 0}, -        [GFS3_OP_ENTRYLK]     = { "ENTRYLK",    GFS3_OP_ENTRYLK, server3_3_entrylk, NULL, 0}, -        [GFS3_OP_FENTRYLK]    = { "FENTRYLK",   GFS3_OP_FENTRYLK, server3_3_fentrylk, NULL, 0}, -        [GFS3_OP_XATTROP]     = { "XATTROP",    GFS3_OP_XATTROP, server3_3_xattrop, NULL, 0}, -        [GFS3_OP_FXATTROP]    = { "FXATTROP",   GFS3_OP_FXATTROP, server3_3_fxattrop, NULL, 0}, -        [GFS3_OP_FGETXATTR]   = { "FGETXATTR",  GFS3_OP_FGETXATTR, server3_3_fgetxattr, NULL, 0}, -        [GFS3_OP_FSETXATTR]   = { "FSETXATTR",  GFS3_OP_FSETXATTR, server3_3_fsetxattr, NULL, 0}, -        [GFS3_OP_RCHECKSUM]   = { "RCHECKSUM",  GFS3_OP_RCHECKSUM, server3_3_rchecksum, NULL, 0}, -        [GFS3_OP_SETATTR]     = { "SETATTR",    GFS3_OP_SETATTR, server3_3_setattr, NULL, 0}, -        [GFS3_OP_FSETATTR]    = { "FSETATTR",   GFS3_OP_FSETATTR, server3_3_fsetattr, NULL, 0}, -        [GFS3_OP_READDIRP]    = { "READDIRP",   GFS3_OP_READDIRP, server3_3_readdirp, NULL, 0}, -        [GFS3_OP_RELEASE]     = { "RELEASE",    GFS3_OP_RELEASE, server3_3_release, NULL, 0}, -        [GFS3_OP_RELEASEDIR]  = { "RELEASEDIR", GFS3_OP_RELEASEDIR, server3_3_releasedir, NULL, 0}, -        [GFS3_OP_FREMOVEXATTR] = { "FREMOVEXATTR", GFS3_OP_FREMOVEXATTR, server3_3_fremovexattr, NULL, 0}, -	[GFS3_OP_FALLOCATE]   = { "FALLOCATE",	GFS3_OP_FALLOCATE, server3_3_fallocate, NULL, 0}, -	[GFS3_OP_DISCARD]     = { "DISCARD",	GFS3_OP_DISCARD, server3_3_discard, NULL, 0}, +        [GFS3_OP_NULL]         = {"NULL",         GFS3_OP_NULL,         server_null,            NULL, 0, DRC_NA}, +        [GFS3_OP_STAT]         = {"STAT",         GFS3_OP_STAT,         server3_3_stat,         NULL, 0, DRC_NA}, +        [GFS3_OP_READLINK]     = {"READLINK",     GFS3_OP_READLINK,     server3_3_readlink,     NULL, 0, DRC_NA}, +        [GFS3_OP_MKNOD]        = {"MKNOD",        GFS3_OP_MKNOD,        server3_3_mknod,        NULL, 0, DRC_NA}, +        [GFS3_OP_MKDIR]        = {"MKDIR",        GFS3_OP_MKDIR,        server3_3_mkdir,        NULL, 0, DRC_NA}, +        [GFS3_OP_UNLINK]       = {"UNLINK",       GFS3_OP_UNLINK,       server3_3_unlink,       NULL, 0, DRC_NA}, +        [GFS3_OP_RMDIR]        = {"RMDIR",        GFS3_OP_RMDIR,        server3_3_rmdir,        NULL, 0, DRC_NA}, +        [GFS3_OP_SYMLINK]      = {"SYMLINK",      GFS3_OP_SYMLINK,      server3_3_symlink,      NULL, 0, DRC_NA}, +        [GFS3_OP_RENAME]       = {"RENAME",       GFS3_OP_RENAME,       server3_3_rename,       NULL, 0, DRC_NA}, +        [GFS3_OP_LINK]         = {"LINK",         GFS3_OP_LINK,         server3_3_link,         NULL, 0, DRC_NA}, +        [GFS3_OP_TRUNCATE]     = {"TRUNCATE",     GFS3_OP_TRUNCATE,     server3_3_truncate,     NULL, 0, DRC_NA}, +        [GFS3_OP_OPEN]         = {"OPEN",         GFS3_OP_OPEN,         server3_3_open,         NULL, 0, DRC_NA}, +        [GFS3_OP_READ]         = {"READ",         GFS3_OP_READ,         server3_3_readv,        NULL, 0, DRC_NA}, +        [GFS3_OP_WRITE]        = {"WRITE",        GFS3_OP_WRITE,        server3_3_writev,       server3_3_writev_vecsizer, 0, DRC_NA}, +        [GFS3_OP_STATFS]       = {"STATFS",       GFS3_OP_STATFS,       server3_3_statfs,       NULL, 0, DRC_NA}, +        [GFS3_OP_FLUSH]        = {"FLUSH",        GFS3_OP_FLUSH,        server3_3_flush,        NULL, 0, DRC_NA}, +        [GFS3_OP_FSYNC]        = {"FSYNC",        GFS3_OP_FSYNC,        server3_3_fsync,        NULL, 0, DRC_NA}, +        [GFS3_OP_SETXATTR]     = {"SETXATTR",     GFS3_OP_SETXATTR,     server3_3_setxattr,     NULL, 0, DRC_NA}, +        [GFS3_OP_GETXATTR]     = {"GETXATTR",     GFS3_OP_GETXATTR,     server3_3_getxattr,     NULL, 0, DRC_NA}, +        [GFS3_OP_REMOVEXATTR]  = {"REMOVEXATTR",  GFS3_OP_REMOVEXATTR,  server3_3_removexattr,  NULL, 0, DRC_NA}, +        [GFS3_OP_OPENDIR]      = {"OPENDIR",      GFS3_OP_OPENDIR,      server3_3_opendir,      NULL, 0, DRC_NA}, +        [GFS3_OP_FSYNCDIR]     = {"FSYNCDIR",     GFS3_OP_FSYNCDIR,     server3_3_fsyncdir,     NULL, 0, DRC_NA}, +        [GFS3_OP_ACCESS]       = {"ACCESS",       GFS3_OP_ACCESS,       server3_3_access,       NULL, 0, DRC_NA}, +        [GFS3_OP_CREATE]       = {"CREATE",       GFS3_OP_CREATE,       server3_3_create,       NULL, 0, DRC_NA}, +        [GFS3_OP_FTRUNCATE]    = {"FTRUNCATE",    GFS3_OP_FTRUNCATE,    server3_3_ftruncate,    NULL, 0, DRC_NA}, +        [GFS3_OP_FSTAT]        = {"FSTAT",        GFS3_OP_FSTAT,        server3_3_fstat,        NULL, 0, DRC_NA}, +        [GFS3_OP_LK]           = {"LK",           GFS3_OP_LK,           server3_3_lk,           NULL, 0, DRC_NA}, +        [GFS3_OP_LOOKUP]       = {"LOOKUP",       GFS3_OP_LOOKUP,       server3_3_lookup,       NULL, 0, DRC_NA}, +        [GFS3_OP_READDIR]      = {"READDIR",      GFS3_OP_READDIR,      server3_3_readdir,      NULL, 0, DRC_NA}, +        [GFS3_OP_INODELK]      = {"INODELK",      GFS3_OP_INODELK,      server3_3_inodelk,      NULL, 0, DRC_NA}, +        [GFS3_OP_FINODELK]     = {"FINODELK",     GFS3_OP_FINODELK,     server3_3_finodelk,     NULL, 0, DRC_NA}, +        [GFS3_OP_ENTRYLK]      = {"ENTRYLK",      GFS3_OP_ENTRYLK,      server3_3_entrylk,      NULL, 0, DRC_NA}, +        [GFS3_OP_FENTRYLK]     = {"FENTRYLK",     GFS3_OP_FENTRYLK,     server3_3_fentrylk,     NULL, 0, DRC_NA}, +        [GFS3_OP_XATTROP]      = {"XATTROP",      GFS3_OP_XATTROP,      server3_3_xattrop,      NULL, 0, DRC_NA}, +        [GFS3_OP_FXATTROP]     = {"FXATTROP",     GFS3_OP_FXATTROP,     server3_3_fxattrop,     NULL, 0, DRC_NA}, +        [GFS3_OP_FGETXATTR]    = {"FGETXATTR",    GFS3_OP_FGETXATTR,    server3_3_fgetxattr,    NULL, 0, DRC_NA}, +        [GFS3_OP_FSETXATTR]    = {"FSETXATTR",    GFS3_OP_FSETXATTR,    server3_3_fsetxattr,    NULL, 0, DRC_NA}, +        [GFS3_OP_RCHECKSUM]    = {"RCHECKSUM",    GFS3_OP_RCHECKSUM,    server3_3_rchecksum,    NULL, 0, DRC_NA}, +        [GFS3_OP_SETATTR]      = {"SETATTR",      GFS3_OP_SETATTR,      server3_3_setattr,      NULL, 0, DRC_NA}, +        [GFS3_OP_FSETATTR]     = {"FSETATTR",     GFS3_OP_FSETATTR,     server3_3_fsetattr,     NULL, 0, DRC_NA}, +        [GFS3_OP_READDIRP]     = {"READDIRP",     GFS3_OP_READDIRP,     server3_3_readdirp,     NULL, 0, DRC_NA}, +        [GFS3_OP_RELEASE]      = {"RELEASE",      GFS3_OP_RELEASE,      server3_3_release,      NULL, 0, DRC_NA}, +        [GFS3_OP_RELEASEDIR]   = {"RELEASEDIR",   GFS3_OP_RELEASEDIR,   server3_3_releasedir,   NULL, 0, DRC_NA}, +        [GFS3_OP_FREMOVEXATTR] = {"FREMOVEXATTR", GFS3_OP_FREMOVEXATTR, server3_3_fremovexattr, NULL, 0, DRC_NA}, +	[GFS3_OP_FALLOCATE]    = {"FALLOCATE",	  GFS3_OP_FALLOCATE,    server3_3_fallocate,    NULL, 0, DRC_NA}, +	[GFS3_OP_DISCARD]      = {"DISCARD",	  GFS3_OP_DISCARD,      server3_3_discard,      NULL, 0, DRC_NA},  };  | 
