"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.2/xlators/mgmt/glusterd/src/glusterd-pmap.c" (16 Sep 2020, 18090 Bytes) of package /linux/misc/glusterfs-8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "glusterd-pmap.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2    Copyright (c) 2010-2013 Red Hat, Inc. <http://www.redhat.com>
    3    This file is part of GlusterFS.
    4 
    5    This file is licensed to you under your choice of the GNU Lesser
    6    General Public License, version 3 or any later version (LGPLv3 or
    7    later), or the GNU General Public License, version 2 (GPLv2), in all
    8    cases as published by the Free Software Foundation.
    9 */
   10 
   11 #include <glusterfs/xlator.h>
   12 #include <glusterfs/glusterfs.h>
   13 #include <glusterfs/syscall.h>
   14 #include <glusterfs/compat-errno.h>
   15 
   16 #include "glusterd.h"
   17 #include "glusterd-utils.h"
   18 
   19 #include "portmap-xdr.h"
   20 #include "xdr-generic.h"
   21 #include "protocol-common.h"
   22 #include "glusterd-messages.h"
   23 #include "rpcsvc.h"
   24 
   25 #include <sys/socket.h>
   26 #include <sys/types.h>
   27 #include <netinet/in.h>
   28 
   29 static int
   30 pmap_port_isfree(int port)
   31 {
   32     struct sockaddr_in sin;
   33     int sock = -1;
   34     int ret = 0;
   35 
   36     memset(&sin, 0, sizeof(sin));
   37     sin.sin_family = PF_INET;
   38     sin.sin_port = hton16(port);
   39 
   40     sock = socket(PF_INET, SOCK_STREAM, 0);
   41     if (sock == -1)
   42         return -1;
   43 
   44     ret = bind(sock, (struct sockaddr *)&sin, sizeof(sin));
   45     sys_close(sock);
   46 
   47     return (ret == 0) ? 1 : 0;
   48 }
   49 
   50 static struct pmap_registry *
   51 pmap_registry_new(xlator_t *this)
   52 {
   53     struct pmap_registry *pmap = NULL;
   54     int i = 0;
   55 
   56     pmap = CALLOC(sizeof(*pmap), 1);
   57     if (!pmap)
   58         return NULL;
   59 
   60     pmap->base_port = pmap->last_alloc = ((glusterd_conf_t *)(this->private))
   61                                              ->base_port;
   62     pmap->max_port = ((glusterd_conf_t *)(this->private))->max_port;
   63     for (i = pmap->base_port; i <= pmap->max_port; i++) {
   64         if (pmap_port_isfree(i))
   65             pmap->ports[i].type = GF_PMAP_PORT_FREE;
   66         else
   67             pmap->ports[i].type = GF_PMAP_PORT_FOREIGN;
   68     }
   69 
   70     return pmap;
   71 }
   72 
   73 struct pmap_registry *
   74 pmap_registry_get(xlator_t *this)
   75 {
   76     glusterd_conf_t *priv = NULL;
   77     struct pmap_registry *pmap = NULL;
   78 
   79     priv = this->private;
   80 
   81     pmap = priv->pmap;
   82     if (!pmap) {
   83         pmap = pmap_registry_new(this);
   84         if (!pmap)
   85             return NULL;
   86         priv->pmap = pmap;
   87     }
   88 
   89     return pmap;
   90 }
   91 
   92 /*
   93  * The "destroy" argument avoids a double search in pmap_registry_remove - one
   94  * to find the entry in the table, and the other to find the particular
   95  * brickname within that entry (which might cover multiple bricks).  We do the
   96  * actual deletion here by "whiting out" the brick name with spaces.  It's up
   97  * to pmap_registry_remove to figure out what to do from there.
   98  */
   99 int
  100 pmap_registry_search(xlator_t *this, const char *brickname,
  101                      gf_pmap_port_type_t type, gf_boolean_t destroy)
  102 {
  103     struct pmap_registry *pmap = NULL;
  104     int p = 0;
  105     char *brck = NULL;
  106     size_t i;
  107 
  108     pmap = pmap_registry_get(this);
  109 
  110     for (p = pmap->last_alloc; p >= pmap->base_port; p--) {
  111         if (!pmap->ports[p].brickname || pmap->ports[p].type != type)
  112             continue;
  113 
  114         brck = pmap->ports[p].brickname;
  115         for (;;) {
  116             for (i = 0; brck[i] && !isspace(brck[i]); ++i)
  117                 ;
  118             if (i == 0 && brck[i] == '\0')
  119                 break;
  120 
  121             if (strncmp(brck, brickname, i) == 0) {
  122                 /*
  123                  * Without this check, we'd break when brck
  124                  * is merely a substring of brickname.
  125                  */
  126                 if (brickname[i] == '\0') {
  127                     if (destroy)
  128                         do {
  129                             *(brck++) = ' ';
  130                         } while (--i);
  131                     return p;
  132                 }
  133             }
  134 
  135             brck += i;
  136 
  137             /*
  138              * Skip over *any* amount of whitespace, including
  139              * none (if we're already at the end of the string).
  140              */
  141             while (isspace(*brck))
  142                 ++brck;
  143             /*
  144              * We're either at the end of the string (which will be
  145              * handled above strncmp on the next iteration) or at
  146              * the next non-whitespace substring (which will be
  147              * handled by strncmp itself).
  148              */
  149         }
  150     }
  151 
  152     return 0;
  153 }
  154 
  155 static int
  156 pmap_registry_search_by_xprt(xlator_t *this, void *xprt,
  157                              gf_pmap_port_type_t type)
  158 {
  159     struct pmap_registry *pmap = NULL;
  160     int p = 0;
  161     int port = 0;
  162 
  163     pmap = pmap_registry_get(this);
  164 
  165     for (p = pmap->last_alloc; p >= pmap->base_port; p--) {
  166         if (!pmap->ports[p].xprt)
  167             continue;
  168         if (pmap->ports[p].xprt == xprt) {
  169             if (pmap->ports[p].type == type || type == GF_PMAP_PORT_ANY) {
  170                 port = p;
  171                 break;
  172             }
  173         }
  174     }
  175 
  176     return port;
  177 }
  178 
  179 static char *
  180 pmap_registry_search_by_port(xlator_t *this, int port)
  181 {
  182     struct pmap_registry *pmap = NULL;
  183     char *brickname = NULL;
  184     int max_port = 0;
  185 
  186     max_port = ((glusterd_conf_t *)(this->private))->max_port;
  187     if (port > max_port)
  188         goto out;
  189 
  190     pmap = pmap_registry_get(this);
  191 
  192     if (pmap->ports[port].type == GF_PMAP_PORT_BRICKSERVER)
  193         brickname = pmap->ports[port].brickname;
  194 
  195 out:
  196     return brickname;
  197 }
  198 
  199 int
  200 pmap_registry_alloc(xlator_t *this)
  201 {
  202     struct pmap_registry *pmap = NULL;
  203     int p = 0;
  204     int port = 0;
  205 
  206     pmap = pmap_registry_get(this);
  207 
  208     for (p = pmap->base_port; p <= pmap->max_port; p++) {
  209         /* GF_PMAP_PORT_FOREIGN may be freed up ? */
  210         if ((pmap->ports[p].type == GF_PMAP_PORT_FREE) ||
  211             (pmap->ports[p].type == GF_PMAP_PORT_FOREIGN)) {
  212             if (pmap_port_isfree(p)) {
  213                 pmap->ports[p].type = GF_PMAP_PORT_LEASED;
  214                 port = p;
  215                 break;
  216             }
  217         }
  218     }
  219 
  220     if (port > pmap->last_alloc)
  221         pmap->last_alloc = port;
  222 
  223     return port;
  224 }
  225 
  226 /* pmap_assign_port does a pmap_registry_remove followed by pmap_registry_alloc,
  227  * the reason for the former is to ensure we don't end up with stale ports
  228  */
  229 int
  230 pmap_assign_port(xlator_t *this, int old_port, const char *path)
  231 {
  232     int ret = -1;
  233     int new_port = 0;
  234 
  235     if (old_port) {
  236         ret = pmap_registry_remove(this, 0, path, GF_PMAP_PORT_BRICKSERVER,
  237                                    NULL, _gf_false);
  238         if (ret) {
  239             gf_msg(this->name, GF_LOG_WARNING, GD_MSG_PMAP_REGISTRY_REMOVE_FAIL,
  240                    0,
  241                    "Failed to"
  242                    "remove pmap registry for older signin for path"
  243                    " %s",
  244                    path);
  245         }
  246     }
  247     new_port = pmap_registry_alloc(this);
  248     return new_port;
  249 }
  250 
  251 int
  252 pmap_registry_bind(xlator_t *this, int port, const char *brickname,
  253                    gf_pmap_port_type_t type, void *xprt)
  254 {
  255     struct pmap_registry *pmap = NULL;
  256     int p = 0;
  257 
  258     pmap = pmap_registry_get(this);
  259 
  260     if (port > pmap->max_port)
  261         goto out;
  262 
  263     p = port;
  264     if (pmap->ports[p].type == GF_PMAP_PORT_FREE) {
  265         /* Because of some crazy race in volume start code path because
  266          * of friend handshaking with volumes with quorum enabled we
  267          * might end up into a situation where glusterd would start a
  268          * brick and get a disconnect and then immediately try to start
  269          * the same brick instance based on another friend update
  270          * request. And then if for the very first brick even if the
  271          * process doesn't come up at the end sign in event gets sent
  272          * and we end up having two duplicate portmap entries for the
  273          * same brick. Since in brick start we mark the previous port as
  274          * free, its better to consider a sign in request as no op if
  275          * the corresponding port type is marked as free
  276          */
  277         goto out;
  278     }
  279     if (pmap->ports[p].brickname) {
  280         char *tmp = pmap->ports[p].brickname;
  281         asprintf(&pmap->ports[p].brickname, "%s %s", tmp, brickname);
  282         free(tmp);
  283     } else {
  284         pmap->ports[p].brickname = strdup(brickname);
  285     }
  286     pmap->ports[p].type = type;
  287     pmap->ports[p].xprt = xprt;
  288 
  289     gf_msg("pmap", GF_LOG_INFO, 0, GD_MSG_BRICK_ADD,
  290            "adding brick %s on port %d", brickname, port);
  291 
  292     if (pmap->last_alloc < p)
  293         pmap->last_alloc = p;
  294 out:
  295     return 0;
  296 }
  297 
  298 int
  299 pmap_registry_extend(xlator_t *this, int port, const char *brickname)
  300 {
  301     struct pmap_registry *pmap = NULL;
  302     char *old_bn;
  303     char *new_bn;
  304     size_t bn_len;
  305     char *entry;
  306     int found = 0;
  307 
  308     pmap = pmap_registry_get(this);
  309 
  310     if (port > pmap->max_port) {
  311         return -1;
  312     }
  313 
  314     switch (pmap->ports[port].type) {
  315         case GF_PMAP_PORT_LEASED:
  316         case GF_PMAP_PORT_BRICKSERVER:
  317             break;
  318         default:
  319             return -1;
  320     }
  321 
  322     old_bn = pmap->ports[port].brickname;
  323     if (old_bn) {
  324         bn_len = strlen(brickname);
  325         entry = strstr(old_bn, brickname);
  326         while (entry) {
  327             found = 1;
  328             if ((entry != old_bn) && (entry[-1] != ' ')) {
  329                 found = 0;
  330             }
  331             if ((entry[bn_len] != ' ') && (entry[bn_len] != '\0')) {
  332                 found = 0;
  333             }
  334             if (found) {
  335                 return 0;
  336             }
  337             entry = strstr(entry + bn_len, brickname);
  338         }
  339         asprintf(&new_bn, "%s %s", old_bn, brickname);
  340     } else {
  341         new_bn = strdup(brickname);
  342     }
  343 
  344     if (!new_bn) {
  345         return -1;
  346     }
  347 
  348     pmap->ports[port].brickname = new_bn;
  349     free(old_bn);
  350 
  351     return 0;
  352 }
  353 
  354 int
  355 pmap_registry_remove(xlator_t *this, int port, const char *brickname,
  356                      gf_pmap_port_type_t type, void *xprt,
  357                      gf_boolean_t brick_disconnect)
  358 {
  359     struct pmap_registry *pmap = NULL;
  360     int p = 0;
  361     glusterd_conf_t *priv = NULL;
  362     char *brick_str;
  363 
  364     priv = this->private;
  365     pmap = priv->pmap;
  366     if (!pmap)
  367         goto out;
  368 
  369     if (port) {
  370         if (port > pmap->max_port)
  371             goto out;
  372     }
  373 
  374     if (brickname) {
  375         p = pmap_registry_search(this, brickname, type, _gf_true);
  376         if (p)
  377             goto remove;
  378     }
  379 
  380     if (xprt) {
  381         p = pmap_registry_search_by_xprt(this, xprt, type);
  382         if (p)
  383             goto remove;
  384     }
  385 
  386     goto out;
  387 remove:
  388     gf_msg("pmap", GF_LOG_INFO, 0, GD_MSG_BRICK_REMOVE,
  389            "removing brick %s on port %d", brickname, p);
  390 
  391     if (xprt && (xprt == pmap->ports[p].xprt)) {
  392         pmap->ports[p].xprt = NULL;
  393     }
  394 
  395     /*
  396      * This is where we garbage-collect.  If all of the brick names have
  397      * been "whited out" by pmap_registry_search(...,destroy=_gf_true) and
  398      * there's no xprt either, then we have nothing left worth saving and
  399      * can delete the entire entry.
  400      */
  401     if (brick_disconnect || !pmap->ports[p].xprt) {
  402         /* If the signout call is being triggered by brick disconnect
  403          * then clean up all the bricks (in case of brick mux)
  404          */
  405         if (!brick_disconnect) {
  406             brick_str = pmap->ports[p].brickname;
  407             if (brick_str) {
  408                 while (*brick_str != '\0') {
  409                     if (*(brick_str++) != ' ') {
  410                         goto out;
  411                     }
  412                 }
  413             }
  414         }
  415         free(pmap->ports[p].brickname);
  416         pmap->ports[p].brickname = NULL;
  417         pmap->ports[p].type = GF_PMAP_PORT_FREE;
  418     }
  419 
  420 out:
  421     return 0;
  422 }
  423 
  424 int
  425 __gluster_pmap_portbybrick(rpcsvc_request_t *req)
  426 {
  427     pmap_port_by_brick_req args = {
  428         0,
  429     };
  430     pmap_port_by_brick_rsp rsp = {
  431         0,
  432     };
  433     char *brick = NULL;
  434     int port = 0;
  435     int ret = -1;
  436 
  437     ret = xdr_to_generic(req->msg[0], &args,
  438                          (xdrproc_t)xdr_pmap_port_by_brick_req);
  439     if (ret < 0) {
  440         req->rpc_err = GARBAGE_ARGS;
  441         goto fail;
  442     }
  443 
  444     brick = args.brick;
  445 
  446     port = pmap_registry_search(THIS, brick, GF_PMAP_PORT_BRICKSERVER,
  447                                 _gf_false);
  448 
  449     if (!port)
  450         rsp.op_ret = -1;
  451 
  452     rsp.port = port;
  453 
  454 fail:
  455     glusterd_submit_reply(req, &rsp, NULL, 0, NULL,
  456                           (xdrproc_t)xdr_pmap_port_by_brick_rsp);
  457     free(args.brick);  // malloced by xdr
  458 
  459     return 0;
  460 }
  461 
  462 int
  463 gluster_pmap_portbybrick(rpcsvc_request_t *req)
  464 {
  465     return glusterd_big_locked_handler(req, __gluster_pmap_portbybrick);
  466 }
  467 
  468 int
  469 __gluster_pmap_brickbyport(rpcsvc_request_t *req)
  470 {
  471     pmap_brick_by_port_req args = {
  472         0,
  473     };
  474     pmap_brick_by_port_rsp rsp = {
  475         0,
  476     };
  477     int ret = -1;
  478 
  479     ret = xdr_to_generic(req->msg[0], &args,
  480                          (xdrproc_t)xdr_pmap_brick_by_port_req);
  481     if (ret < 0) {
  482         req->rpc_err = GARBAGE_ARGS;
  483         goto fail;
  484     }
  485 
  486     rsp.brick = pmap_registry_search_by_port(THIS, args.port);
  487     if (!rsp.brick) {
  488         rsp.op_ret = -1;
  489         rsp.brick = "";
  490     }
  491 fail:
  492 
  493     glusterd_submit_reply(req, &rsp, NULL, 0, NULL,
  494                           (xdrproc_t)xdr_pmap_brick_by_port_rsp);
  495 
  496     return 0;
  497 }
  498 
  499 int
  500 gluster_pmap_brickbyport(rpcsvc_request_t *req)
  501 {
  502     return glusterd_big_locked_handler(req, __gluster_pmap_brickbyport);
  503 }
  504 
  505 int
  506 __gluster_pmap_signin(rpcsvc_request_t *req)
  507 {
  508     pmap_signin_req args = {
  509         0,
  510     };
  511     pmap_signin_rsp rsp = {
  512         0,
  513     };
  514     int ret = -1;
  515     glusterd_brickinfo_t *brickinfo = NULL;
  516 
  517     ret = xdr_to_generic(req->msg[0], &args, (xdrproc_t)xdr_pmap_signin_req);
  518     if (ret < 0) {
  519         req->rpc_err = GARBAGE_ARGS;
  520         goto fail;
  521     }
  522 
  523     rsp.op_ret = pmap_registry_bind(THIS, args.port, args.brick,
  524                                     GF_PMAP_PORT_BRICKSERVER, req->trans);
  525 
  526     ret = glusterd_get_brickinfo(THIS, args.brick, args.port, &brickinfo);
  527     /* Update portmap status in brickinfo */
  528     if (brickinfo)
  529         brickinfo->port_registered = _gf_true;
  530 
  531 fail:
  532     glusterd_submit_reply(req, &rsp, NULL, 0, NULL,
  533                           (xdrproc_t)xdr_pmap_signin_rsp);
  534     free(args.brick);  // malloced by xdr
  535 
  536     return 0;
  537 }
  538 
  539 int
  540 gluster_pmap_signin(rpcsvc_request_t *req)
  541 {
  542     return glusterd_big_locked_handler(req, __gluster_pmap_signin);
  543 }
  544 
  545 int
  546 __gluster_pmap_signout(rpcsvc_request_t *req)
  547 {
  548     pmap_signout_req args = {
  549         0,
  550     };
  551     pmap_signout_rsp rsp = {
  552         0,
  553     };
  554     int ret = -1;
  555     xlator_t *this = NULL;
  556     glusterd_conf_t *conf = NULL;
  557     glusterd_volinfo_t *volinfo = NULL;
  558     glusterd_brickinfo_t *brickinfo = NULL;
  559     char pidfile[PATH_MAX] = {0};
  560     char brick_path[PATH_MAX] = {
  561         0,
  562     };
  563 
  564     this = THIS;
  565     GF_VALIDATE_OR_GOTO("glusterd", this, fail);
  566     conf = this->private;
  567     GF_VALIDATE_OR_GOTO(this->name, conf, fail);
  568 
  569     ret = xdr_to_generic(req->msg[0], &args, (xdrproc_t)xdr_pmap_signout_req);
  570     if (ret < 0) {
  571         // failed to decode msg;
  572         req->rpc_err = GARBAGE_ARGS;
  573         goto fail;
  574     }
  575     rsp.op_ret = pmap_registry_remove(THIS, args.port, args.brick,
  576                                       GF_PMAP_PORT_BRICKSERVER, req->trans,
  577                                       _gf_false);
  578 
  579     ret = glusterd_get_brickinfo(THIS, args.brick, args.port, &brickinfo);
  580     if (args.rdma_port) {
  581         snprintf(brick_path, PATH_MAX, "%s.rdma", args.brick);
  582         rsp.op_ret = pmap_registry_remove(THIS, args.rdma_port, brick_path,
  583                                           GF_PMAP_PORT_BRICKSERVER, req->trans,
  584                                           _gf_false);
  585     }
  586     /* Update portmap status on brickinfo */
  587     if (brickinfo)
  588         brickinfo->port_registered = _gf_false;
  589 
  590     /* Clean up the pidfile for this brick given glusterfsd doesn't clean it
  591      * any more. This is required to ensure we don't end up with having
  592      * stale pid files in case a brick is killed from the backend
  593      */
  594     ret = glusterd_get_volinfo_from_brick(args.brick, &volinfo);
  595     if (!ret) {
  596         if (volinfo && brickinfo) {
  597             GLUSTERD_GET_BRICK_PIDFILE(pidfile, volinfo, brickinfo, conf);
  598             sys_unlink(pidfile);
  599 
  600             /* Setting the brick status to GF_BRICK_STOPPED to
  601              * ensure correct brick status is maintained on the
  602              * glusterd end when a brick is killed from the
  603              * backend */
  604             brickinfo->status = GF_BRICK_STOPPED;
  605 
  606             /* Remove brick from brick process if not already
  607              * removed in the brick op phase. This situation would
  608              * arise when the brick is killed explicitly from the
  609              * backend */
  610             ret = glusterd_brick_process_remove_brick(brickinfo, NULL);
  611             if (ret) {
  612                 gf_msg_debug(this->name, 0,
  613                              "Couldn't remove "
  614                              "brick %s:%s from brick process",
  615                              brickinfo->hostname, brickinfo->path);
  616                 /* Ignore 'ret' here since the brick might
  617                  * have already been deleted in brick op phase
  618                  */
  619                 ret = 0;
  620             }
  621         }
  622     }
  623 
  624 fail:
  625     glusterd_submit_reply(req, &rsp, NULL, 0, NULL,
  626                           (xdrproc_t)xdr_pmap_signout_rsp);
  627     free(args.brick);  // malloced by xdr
  628 
  629     return 0;
  630 }
  631 
  632 int
  633 gluster_pmap_signout(rpcsvc_request_t *req)
  634 {
  635     return glusterd_big_locked_handler(req, __gluster_pmap_signout);
  636 }
  637 
  638 static rpcsvc_actor_t gluster_pmap_actors[GF_PMAP_MAXVALUE] = {
  639     [GF_PMAP_NULL] = {"NULL", NULL, NULL, GF_PMAP_NULL, DRC_NA, 0},
  640     [GF_PMAP_PORTBYBRICK] = {"PORTBYBRICK", gluster_pmap_portbybrick, NULL,
  641                              GF_PMAP_PORTBYBRICK, DRC_NA, 0},
  642     [GF_PMAP_BRICKBYPORT] = {"BRICKBYPORT", gluster_pmap_brickbyport, NULL,
  643                              GF_PMAP_BRICKBYPORT, DRC_NA, 0},
  644     [GF_PMAP_SIGNIN] = {"SIGNIN", gluster_pmap_signin, NULL, GF_PMAP_SIGNIN,
  645                         DRC_NA, 0},
  646     [GF_PMAP_SIGNOUT] = {"SIGNOUT", gluster_pmap_signout, NULL, GF_PMAP_SIGNOUT,
  647                          DRC_NA, 0},
  648 };
  649 
  650 struct rpcsvc_program gluster_pmap_prog = {
  651     .progname = "Gluster Portmap",
  652     .prognum = GLUSTER_PMAP_PROGRAM,
  653     .progver = GLUSTER_PMAP_VERSION,
  654     .actors = gluster_pmap_actors,
  655     .numactors = GF_PMAP_MAXVALUE,
  656 };