summaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
authorJeff Darcy <jdarcy@redhat.com>2014-04-28 14:18:50 +0000
committerJeff Darcy <jdarcy@redhat.com>2014-04-28 14:18:50 +0000
commite139b4d0ba2286c0d4d44ba81260c2b287016019 (patch)
tree0a21f0761528e0f79da0a9f67106eb128ace0cf7 /doc
parent73b60c87ca7f62517a8466431f5a8cf167589c8c (diff)
parentf2bac9f9d5b9956969ddd25a54bc636b82f6923e (diff)
Merge branch 'upstream'HEADmaster
Conflicts: rpc/xdr/src/glusterfs3-xdr.c rpc/xdr/src/glusterfs3-xdr.h xlators/features/changelog/src/Makefile.am xlators/features/changelog/src/changelog-helpers.h xlators/features/changelog/src/changelog.c xlators/mgmt/glusterd/src/glusterd-sm.c Change-Id: I9972a5e6184503477eb77a8b56c50a4db4eec3e2
Diffstat (limited to 'doc')
-rw-r--r--doc/admin-guide/en-US/markdown/admin_managing_volumes.md2
-rw-r--r--doc/features/worm.md75
2 files changed, 76 insertions, 1 deletions
diff --git a/doc/admin-guide/en-US/markdown/admin_managing_volumes.md b/doc/admin-guide/en-US/markdown/admin_managing_volumes.md
index f59134b80..b456e27af 100644
--- a/doc/admin-guide/en-US/markdown/admin_managing_volumes.md
+++ b/doc/admin-guide/en-US/markdown/admin_managing_volumes.md
@@ -188,7 +188,7 @@ set).
For example, to remove server2:/exp2:
- # gluster volume remove-brick test-volume server2:/exp2
+ # gluster volume remove-brick test-volume server2:/exp2 force
Removing brick(s) can result in data loss. Do you want to Continue? (y/n)
diff --git a/doc/features/worm.md b/doc/features/worm.md
new file mode 100644
index 000000000..dba99777d
--- /dev/null
+++ b/doc/features/worm.md
@@ -0,0 +1,75 @@
+#WORM (Write Once Read Many)
+This features enables you to create a `WORM volume` using gluster CLI.
+##Description
+WORM (write once,read many) is a desired feature for users who want to store data such as `log files` and where data is not allowed to get modified.
+
+GlusterFS provides a new key `features.worm` which takes boolean values(enable/disable) for volume set.
+
+Internally, the volume set command with 'feature.worm' key will add 'features/worm' translator in the brick's volume file.
+
+`This change would be reflected on a subsequent restart of the volume`, i.e gluster volume stop, followed by a gluster volume start.
+
+With a volume converted to WORM, the changes are as follows:
+
+* Reads are handled normally
+* Only files with O_APPEND flag will be supported.
+* Truncation,deletion wont be supported.
+
+##Volume Options
+Use the volume set command on a volume and see if the volume is actually turned into WORM type.
+
+ # features.worm enable
+##Fully loaded Example
+WORM feature is being supported from glusterfs version 3.4
+start glusterd by using the command
+
+ # service glusterd start
+Now create a volume by using the command
+
+ # gluster volume create <vol_name> <brick_path>
+start the volume created by running the command below.
+
+ # gluster vol start <vol_name>
+Run the command below to make sure that volume is created.
+
+ # gluster volume info
+Now turn on the WORM feature on the volume by using the command
+
+ # gluster vol set <vol_name> worm enable
+Verify that the option is set by using the command
+
+ # gluster volume info
+User should be able to see another option in the volume info
+
+ # features.worm: enable
+Now restart the volume for the changes to reflect, by performing volume stop and start.
+
+ # gluster volume <vol_name> stop
+ # gluster volume <vol_name> start
+Now mount the volume using fuse mount
+
+ # mount -t glusterfs <vol_name> <mnt_point>
+create a file inside the mount point by running the command below
+
+ # touch <file_name>
+Verify that user is able to create a file by running the command below
+
+ # ls <file_name>
+
+##How To Test
+Now try deleting the above file which is been created
+
+ # rm <file_name>
+Since WORM is enabled on the volume, it gives the following error message `rm: cannot remove '/<mnt_point>/<file_name>': Read-only file system`
+
+put some content into the file which is created above.
+
+ # echo "at the end of the file" >> <file_name>
+Now try editing the file by running the commnad below and verify that the following error message is displayed `rm: cannot remove '/<mnt_point>/<file_name>': Read-only file system`
+
+ # sed -i "1iAt the beginning of the file" <file_name>
+Now read the contents of the file and verify that file can be read.
+
+ cat <file_name>
+
+`Note: If WORM option is set on the volume before it is started, then volume need not be restarted for the changes to get reflected`.
241' href='#n241'>241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
/*
   Copyright (c) 2010-2013 Red Hat, Inc. <http://www.redhat.com>
   This file is part of GlusterFS.

   This file is licensed to you under your choice of the GNU Lesser
   General Public License, version 3 or any later version (LGPLv3 or
   later), or the GNU General Public License, version 2 (GPLv2), in all
   cases as published by the Free Software Foundation.
*/

#include "xlator.h"
#include "glusterfs.h"
#include "syscall.h"
#include "compat-errno.h"

#include "glusterd.h"
#include "glusterd-utils.h"

#include "portmap-xdr.h"
#include "xdr-generic.h"
#include "protocol-common.h"
#include "glusterd-messages.h"
#include "rpcsvc.h"

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>


static int
pmap_port_isfree (int port)
{
        struct sockaddr_in sin;
        int                sock = -1;
        int                ret = 0;

        memset (&sin, 0, sizeof (sin));
        sin.sin_family = PF_INET;
        sin.sin_port = hton16 (port);

        sock = socket (PF_INET, SOCK_STREAM, 0);
        if (sock == -1)
                return -1;

        ret = bind (sock, (struct sockaddr *)&sin, sizeof (sin));
        sys_close (sock);

        return (ret == 0) ? 1 : 0;
}


static struct pmap_registry *
pmap_registry_new (xlator_t *this)
{
        struct pmap_registry *pmap = NULL;
        int                   i = 0;

        pmap = CALLOC (sizeof (*pmap), 1);
        if (!pmap)
                return NULL;

        pmap->base_port = pmap->last_alloc =
                ((glusterd_conf_t *)(this->private))->base_port;
        pmap->max_port = ((glusterd_conf_t *)(this->private))->max_port;
        for (i = pmap->base_port; i <= pmap->max_port; i++) {
                if (pmap_port_isfree (i))
                        pmap->ports[i].type = GF_PMAP_PORT_FREE;
                else
                        pmap->ports[i].type = GF_PMAP_PORT_FOREIGN;
        }

        return pmap;
}


struct pmap_registry *
pmap_registry_get (xlator_t *this)
{
        glusterd_conf_t      *priv = NULL;
        struct pmap_registry *pmap = NULL;

        priv = this->private;

        pmap = priv->pmap;
        if (!pmap) {
                pmap = pmap_registry_new (this);
                if (!pmap)
                        return NULL;
                priv->pmap = pmap;
        }

        return pmap;
}


/*
 * The "destroy" argument avoids a double search in pmap_registry_remove - one
 * to find the entry in the table, and the other to find the particular
 * brickname within that entry (which might cover multiple bricks).  We do the
 * actual deletion here by "whiting out" the brick name with spaces.  It's up
 * to pmap_registry_remove to figure out what to do from there.
 */
int
pmap_registry_search (xlator_t *this, const char *brickname,
                      gf_pmap_port_type_t type, gf_boolean_t destroy)
{
        struct pmap_registry *pmap = NULL;
        int                   p = 0;
        char                 *brck = NULL;
        size_t                i;

        pmap = pmap_registry_get (this);

        for (p = pmap->last_alloc; p >= pmap->base_port; p--) {
                if (!pmap->ports[p].brickname || pmap->ports[p].type != type)
                        continue;

                brck = pmap->ports[p].brickname;
                for (;;) {
                        for (i = 0; brck[i] && !isspace (brck[i]); ++i)
                                ;
                        if (i == 0 && brck[i] == '\0')
                                break;

                        if (strncmp (brck, brickname, i) == 0) {
                                /*
                                 * Without this check, we'd break when brck
                                 * is merely a substring of brickname.
                                 */
                                if (brickname[i] == '\0') {
                                        if (destroy) do {
                                                *(brck++) = ' ';
                                        } while (--i);
                                        return p;
                                }
                        }

                        brck += i;

                        /*
                         * Skip over *any* amount of whitespace, including
                         * none (if we're already at the end of the string).
                         */
                        while (isspace (*brck))
                                ++brck;
                        /*
                         * We're either at the end of the string (which will be
                         * handled above strncmp on the next iteration) or at
                         * the next non-whitespace substring (which will be
                         * handled by strncmp itself).
                         */
                }
        }

        return 0;
}

static int
pmap_registry_search_by_xprt (xlator_t *this, void *xprt,
                              gf_pmap_port_type_t type)
{
        struct pmap_registry *pmap = NULL;
        int                   p    = 0;
        int                   port = 0;

        pmap = pmap_registry_get (this);

        for (p = pmap->last_alloc; p >= pmap->base_port; p--) {
                if (!pmap->ports[p].xprt)
                        continue;
                if (pmap->ports[p].xprt == xprt) {
                        if (pmap->ports[p].type == type ||
                                        type == GF_PMAP_PORT_ANY) {
                                port = p;
                                break;
                        }
                }
        }

        return port;
}


static char *
pmap_registry_search_by_port (xlator_t *this, int port)
{
        struct  pmap_registry *pmap = NULL;
        char   *brickname           = NULL;
        int     max_port            = 0;

        max_port = ((glusterd_conf_t *)(this->private))->max_port;
        if (port > max_port)
                goto out;

        pmap = pmap_registry_get (this);

        if (pmap->ports[port].type == GF_PMAP_PORT_BRICKSERVER)
                brickname = pmap->ports[port].brickname;

out:
        return brickname;
}


int
pmap_registry_alloc (xlator_t *this)
{
        struct pmap_registry *pmap = NULL;
        int                   p = 0;
        int                   port = 0;

        pmap = pmap_registry_get (this);

        for (p = pmap->base_port; p <= pmap->max_port; p++) {
                /* GF_PMAP_PORT_FOREIGN may be freed up ? */
                if ((pmap->ports[p].type == GF_PMAP_PORT_FREE) ||
                    (pmap->ports[p].type == GF_PMAP_PORT_FOREIGN)) {

                        if (pmap_port_isfree (p)) {
                                pmap->ports[p].type = GF_PMAP_PORT_LEASED;
                                port = p;
                                break;
                        }
                }
        }

        if (port > pmap->last_alloc)
                pmap->last_alloc = port;

        return port;
}

/* pmap_assign_port does a pmap_registry_remove followed by pmap_registry_alloc,
 * the reason for the former is to ensure we don't end up with stale ports
 */
int
pmap_assign_port (xlator_t *this, int old_port, const char *path)
{
        int ret = -1;
        int new_port = 0;

        if (old_port) {
                ret = pmap_registry_remove (this, 0, path,
                                            GF_PMAP_PORT_BRICKSERVER, NULL,
                                            _gf_false);
                if (ret) {
                        gf_msg (this->name, GF_LOG_WARNING,
                                GD_MSG_PMAP_REGISTRY_REMOVE_FAIL, 0, "Failed to"
                                "remove pmap registry for older signin for path"
                                " %s", path);
                }
        }
        new_port = pmap_registry_alloc (this);
        return new_port;
}

int
pmap_registry_bind (xlator_t *this, int port, const char *brickname,
                    gf_pmap_port_type_t type, void *xprt)
{
        struct pmap_registry *pmap = NULL;
        int                   p = 0;

        pmap = pmap_registry_get (this);

        if (port > pmap->max_port)
                goto out;

        p = port;
        if (pmap->ports[p].brickname) {
                char *tmp = pmap->ports[p].brickname;
                asprintf (&pmap->ports[p].brickname, "%s %s", tmp, brickname);
                free (tmp);
        } else {
                pmap->ports[p].brickname = strdup (brickname);
        }
        pmap->ports[p].type = type;
        pmap->ports[p].xprt = xprt;

        gf_msg ("pmap", GF_LOG_INFO, 0,
                GD_MSG_BRICK_ADD, "adding brick %s on port %d",
                brickname, port);

        if (pmap->last_alloc < p)
                pmap->last_alloc = p;
out:
        return 0;
}

int
pmap_registry_extend (xlator_t *this, int port, const char *brickname)
{
        struct pmap_registry *pmap = NULL;
        char                 *old_bn;
        char                 *new_bn;
        size_t               bn_len;
        char                 *entry;
        int                  found = 0;

        pmap = pmap_registry_get (this);

        if (port > pmap->max_port) {
                return -1;
        }

        switch (pmap->ports[port].type) {
        case GF_PMAP_PORT_LEASED:
        case GF_PMAP_PORT_BRICKSERVER:
                break;
        default:
                return -1;
        }

        old_bn = pmap->ports[port].brickname;
        if (old_bn) {
                bn_len = strlen(brickname);
                entry = strstr (old_bn, brickname);
                while (entry) {
                        found = 1;
                        if ((entry != old_bn) && (entry[-1] != ' ')) {
                                found = 0;
                        }
                        if ((entry[bn_len] != ' ') && (entry[bn_len] != '\0')) {
                                found = 0;
                        }
                        if (found) {
                                return 0;
                        }
                        entry = strstr (entry + bn_len, brickname);
                }
                asprintf (&new_bn, "%s %s", old_bn, brickname);
        } else {
                new_bn = strdup (brickname);
        }

        if (!new_bn) {
                return -1;
        }

        pmap->ports[port].brickname = new_bn;
        free (old_bn);

        return 0;
}

int
pmap_registry_remove (xlator_t *this, int port, const char *brickname,
                      gf_pmap_port_type_t type, void *xprt,
                      gf_boolean_t brick_disconnect)
{
        struct pmap_registry *pmap = NULL;
        int                   p = 0;
        glusterd_conf_t      *priv = NULL;
        char                 *brick_str;

        priv = this->private;
        pmap = priv->pmap;
        if (!pmap)
                goto out;

        if (port) {
                if (port > pmap->max_port)
                        goto out;

                p = port;
        }

        if (brickname) {
                p = pmap_registry_search (this, brickname, type, _gf_true);
                if (p)
                        goto remove;
        }

        if (xprt) {
                p = pmap_registry_search_by_xprt (this, xprt, type);
                if (p)
                        goto remove;
        }

        goto out;
remove:
        gf_msg ("pmap", GF_LOG_INFO, 0, GD_MSG_BRICK_REMOVE,
                "removing brick %s on port %d", brickname, p);

        if (xprt && (xprt == pmap->ports[p].xprt)) {
                pmap->ports[p].xprt = NULL;
        }

        /*
         * This is where we garbage-collect.  If all of the brick names have
         * been "whited out" by pmap_registry_search(...,destroy=_gf_true) and
         * there's no xprt either, then we have nothing left worth saving and
         * can delete the entire entry.
         */
        if (!pmap->ports[p].xprt) {
                /* If the signout call is being triggered by brick disconnect
                 * then clean up all the bricks (in case of brick mux)
                 */
                if (!brick_disconnect) {
                        brick_str = pmap->ports[p].brickname;
                        if (brick_str) {
                                while (*brick_str != '\0') {
                                        if (*(brick_str++) != ' ') {
                                                goto out;
                                        }
                                }
                        }
                }
                free (pmap->ports[p].brickname);
                pmap->ports[p].brickname = NULL;
                pmap->ports[p].type = GF_PMAP_PORT_FREE;
        }

out:
        return 0;
}

int
__gluster_pmap_portbybrick (rpcsvc_request_t *req)
{
        pmap_port_by_brick_req    args = {0,};
        pmap_port_by_brick_rsp    rsp  = {0,};
        char                     *brick = NULL;
        int                       port = 0;
        int                       ret = -1;

        ret = xdr_to_generic (req->msg[0], &args,
                              (xdrproc_t)xdr_pmap_port_by_brick_req);
        if (ret < 0) {
                req->rpc_err = GARBAGE_ARGS;
                goto fail;
        }

        brick = args.brick;

        port = pmap_registry_search (THIS, brick, GF_PMAP_PORT_BRICKSERVER,
                                     _gf_false);

        if (!port)
                rsp.op_ret = -1;

        rsp.port = port;

fail:
        glusterd_submit_reply (req, &rsp, NULL, 0, NULL,
                               (xdrproc_t)xdr_pmap_port_by_brick_rsp);
        free (args.brick);//malloced by xdr

        return 0;
}


int
gluster_pmap_portbybrick (rpcsvc_request_t *req)
{
        return glusterd_big_locked_handler (req, __gluster_pmap_portbybrick);
}


int
__gluster_pmap_brickbyport (rpcsvc_request_t *req)
{
        pmap_brick_by_port_req    args = {0,};
        pmap_brick_by_port_rsp    rsp  = {0,};
        int                       ret = -1;

        ret = xdr_to_generic (req->msg[0], &args,
                              (xdrproc_t)xdr_pmap_brick_by_port_req);
        if (ret < 0) {
                req->rpc_err = GARBAGE_ARGS;
                goto fail;
        }

        rsp.brick = pmap_registry_search_by_port (THIS, args.port);
        if (!rsp.brick) {
                rsp.op_ret = -1;
                rsp.brick = "";
        }
fail:

        glusterd_submit_reply (req, &rsp, NULL, 0, NULL,
                               (xdrproc_t)xdr_pmap_brick_by_port_rsp);

        return 0;
}


int
gluster_pmap_brickbyport (rpcsvc_request_t *req)
{
        return glusterd_big_locked_handler (req, __gluster_pmap_brickbyport);
}


int
__gluster_pmap_signin (rpcsvc_request_t *req)
{
        pmap_signin_req    args = {0,};
        pmap_signin_rsp    rsp  = {0,};
        int                ret = -1;
        glusterd_brickinfo_t    *brickinfo = NULL;

        ret = xdr_to_generic (req->msg[0], &args,
                              (xdrproc_t)xdr_pmap_signin_req);
        if (ret < 0) {
                req->rpc_err = GARBAGE_ARGS;
                goto fail;
        }

        rsp.op_ret = pmap_registry_bind (THIS, args.port, args.brick,
                                         GF_PMAP_PORT_BRICKSERVER, req->trans);

        ret = glusterd_get_brickinfo (THIS, args.brick, args.port, &brickinfo);
        /* Update portmap status in brickinfo */
        if (brickinfo)
                brickinfo->port_registered = _gf_true;

fail:
        glusterd_submit_reply (req, &rsp, NULL, 0, NULL,
                               (xdrproc_t)xdr_pmap_signin_rsp);
        free (args.brick);//malloced by xdr

        return 0;
}


int
gluster_pmap_signin (rpcsvc_request_t *req)
{
        return glusterd_big_locked_handler (req, __gluster_pmap_signin);
}


int
__gluster_pmap_signout (rpcsvc_request_t *req)
{
        pmap_signout_req      args                 = {0,};
        pmap_signout_rsp      rsp                  = {0,};
        int                   ret                  = -1;
        xlator_t             *this                 = NULL;
        glusterd_conf_t      *conf                 = NULL;
        glusterd_volinfo_t   *volinfo              = NULL;
        glusterd_brickinfo_t *brickinfo            = NULL;
        char                  pidfile[PATH_MAX]    = {0};
        char                  brick_path[PATH_MAX] = {0,};

        this = THIS;
        GF_VALIDATE_OR_GOTO ("glusterd", this, fail);
        conf = this->private;
        GF_VALIDATE_OR_GOTO (this->name, conf, fail);

        ret = xdr_to_generic (req->msg[0], &args,
                              (xdrproc_t)xdr_pmap_signout_req);
        if (ret < 0) {
                //failed to decode msg;
                req->rpc_err = GARBAGE_ARGS;
                goto fail;
        }
        rsp.op_ret = pmap_registry_remove (THIS, args.port, args.brick,
                                           GF_PMAP_PORT_BRICKSERVER, req->trans,
                                           _gf_false);

        ret = glusterd_get_brickinfo (THIS, args.brick, args.port, &brickinfo);
        if (args.rdma_port) {
                snprintf(brick_path, PATH_MAX, "%s.rdma", args.brick);
                rsp.op_ret = pmap_registry_remove (THIS, args.rdma_port,
                                brick_path, GF_PMAP_PORT_BRICKSERVER,
                                req->trans, _gf_false);
        }
        /* Update portmap status on brickinfo */
        if (brickinfo)
                brickinfo->port_registered = _gf_false;

        /* Clean up the pidfile for this brick given glusterfsd doesn't clean it
         * any more. This is required to ensure we don't end up with having
         * stale pid files in case a brick is killed from the backend
         */
        ret = glusterd_get_volinfo_from_brick (args.brick, &volinfo);
        if (!ret) {
                if (volinfo && brickinfo) {
                        GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, brickinfo,
                                                    conf);
                        sys_unlink (pidfile);

                        /* Setting the brick status to GF_BRICK_STOPPED to
                         * ensure correct brick status is maintained on the
                         * glusterd end when a brick is killed from the
                         * backend */
                        brickinfo->status = GF_BRICK_STOPPED;

                        /* Remove brick from brick process if not already
                         * removed in the brick op phase. This situation would
                         * arise when the brick is killed explicitly from the
                         * backend */
                        ret = glusterd_brick_process_remove_brick (brickinfo);
                        if (ret) {
                                gf_msg_debug (this->name, 0, "Couldn't remove "
                                              "brick %s:%s from brick process",
                                              brickinfo->hostname,
                                              brickinfo->path);
                                /* Ignore 'ret' here since the brick might
                                 * have already been deleted in brick op phase
                                 */
                                ret = 0;
                        }
                }
        }

fail:
        glusterd_submit_reply (req, &rsp, NULL, 0, NULL,
                               (xdrproc_t)xdr_pmap_signout_rsp);
        free (args.brick);//malloced by xdr

        return 0;
}

int
gluster_pmap_signout (rpcsvc_request_t *req)
{
        return glusterd_big_locked_handler (req, __gluster_pmap_signout);
}

rpcsvc_actor_t gluster_pmap_actors[GF_PMAP_MAXVALUE] = {
        [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},
};


struct rpcsvc_program gluster_pmap_prog = {
        .progname  = "Gluster Portmap",
        .prognum   = GLUSTER_PMAP_PROGRAM,
        .progver   = GLUSTER_PMAP_VERSION,
        .actors    = gluster_pmap_actors,
        .numactors = GF_PMAP_MAXVALUE,
};