"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-6.9/xlators/cluster/afr/src/afr-self-heal-name.c" (23 Apr 2020, 19801 Bytes) of package /linux/misc/glusterfs-6.9.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 "afr-self-heal-name.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.8_vs_6.9.

    1 /*
    2   Copyright (c) 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/events.h>
   12 #include "afr.h"
   13 #include "afr-self-heal.h"
   14 #include "afr-messages.h"
   15 
   16 int
   17 __afr_selfheal_assign_gfid(xlator_t *this, inode_t *parent, uuid_t pargfid,
   18                            const char *bname, inode_t *inode,
   19                            struct afr_reply *replies, void *gfid,
   20                            unsigned char *locked_on, int source,
   21                            unsigned char *sources, gf_boolean_t is_gfid_absent,
   22                            int *gfid_idx)
   23 {
   24     int ret = 0;
   25     int up_count = 0;
   26     int locked_count = 0;
   27     afr_private_t *priv = NULL;
   28 
   29     priv = this->private;
   30 
   31     gf_uuid_copy(parent->gfid, pargfid);
   32 
   33     if (is_gfid_absent) {
   34         /* Ensure all children of AFR are up before performing gfid heal, to
   35          * guard against the possibility of gfid split brain. */
   36 
   37         up_count = AFR_COUNT(priv->child_up, priv->child_count);
   38         if (up_count != priv->child_count) {
   39             ret = -EIO;
   40             goto out;
   41         }
   42 
   43         locked_count = AFR_COUNT(locked_on, priv->child_count);
   44         if (locked_count != priv->child_count) {
   45             ret = -EIO;
   46             goto out;
   47         }
   48     }
   49 
   50     ret = afr_lookup_and_heal_gfid(this, parent, bname, inode, replies, source,
   51                                    sources, gfid, gfid_idx);
   52 
   53 out:
   54     return ret;
   55 }
   56 
   57 int
   58 __afr_selfheal_name_impunge(call_frame_t *frame, xlator_t *this,
   59                             inode_t *parent, uuid_t pargfid, const char *bname,
   60                             inode_t *inode, struct afr_reply *replies,
   61                             int gfid_idx)
   62 {
   63     int i = 0;
   64     afr_private_t *priv = NULL;
   65     int ret = 0;
   66     unsigned char *sources = NULL;
   67 
   68     priv = this->private;
   69 
   70     sources = alloca0(priv->child_count);
   71 
   72     gf_uuid_copy(parent->gfid, pargfid);
   73 
   74     for (i = 0; i < priv->child_count; i++) {
   75         if (!replies[i].valid || replies[i].op_ret != 0)
   76             continue;
   77 
   78         if (gf_uuid_compare(replies[i].poststat.ia_gfid,
   79                             replies[gfid_idx].poststat.ia_gfid) == 0) {
   80             sources[i] = 1;
   81             continue;
   82         }
   83     }
   84 
   85     for (i = 0; i < priv->child_count; i++) {
   86         if (sources[i])
   87             continue;
   88 
   89         ret |= afr_selfheal_recreate_entry(frame, i, gfid_idx, sources, parent,
   90                                            bname, inode, replies);
   91     }
   92 
   93     return ret;
   94 }
   95 
   96 int
   97 __afr_selfheal_name_expunge(xlator_t *this, inode_t *parent, uuid_t pargfid,
   98                             const char *bname, inode_t *inode,
   99                             struct afr_reply *replies)
  100 {
  101     loc_t loc = {
  102         0,
  103     };
  104     int i = 0;
  105     afr_private_t *priv = NULL;
  106     char g[64];
  107     int ret = 0;
  108 
  109     priv = this->private;
  110 
  111     loc.parent = inode_ref(parent);
  112     gf_uuid_copy(loc.pargfid, pargfid);
  113     loc.name = bname;
  114     loc.inode = inode_ref(inode);
  115 
  116     for (i = 0; i < priv->child_count; i++) {
  117         if (!replies[i].valid)
  118             continue;
  119 
  120         if (replies[i].op_ret)
  121             continue;
  122 
  123         switch (replies[i].poststat.ia_type) {
  124             case IA_IFDIR:
  125                 gf_msg(this->name, GF_LOG_WARNING, 0,
  126                        AFR_MSG_EXPUNGING_FILE_OR_DIR,
  127                        "expunging dir %s/%s (%s) on %s", uuid_utoa(pargfid),
  128                        bname, uuid_utoa_r(replies[i].poststat.ia_gfid, g),
  129                        priv->children[i]->name);
  130 
  131                 ret |= syncop_rmdir(priv->children[i], &loc, 1, NULL, NULL);
  132                 break;
  133             default:
  134                 gf_msg(this->name, GF_LOG_WARNING, 0,
  135                        AFR_MSG_EXPUNGING_FILE_OR_DIR,
  136                        "expunging file %s/%s (%s) on %s", uuid_utoa(pargfid),
  137                        bname, uuid_utoa_r(replies[i].poststat.ia_gfid, g),
  138                        priv->children[i]->name);
  139 
  140                 ret |= syncop_unlink(priv->children[i], &loc, NULL, NULL);
  141                 break;
  142         }
  143     }
  144 
  145     loc_wipe(&loc);
  146 
  147     return ret;
  148 }
  149 
  150 static gf_boolean_t
  151 afr_selfheal_name_need_heal_check(xlator_t *this, struct afr_reply *replies)
  152 {
  153     int i = 0;
  154     int first_idx = -1;
  155     gf_boolean_t need_heal = _gf_false;
  156     afr_private_t *priv = NULL;
  157 
  158     priv = this->private;
  159 
  160     for (i = 0; i < priv->child_count; i++) {
  161         if (!replies[i].valid)
  162             continue;
  163 
  164         if ((replies[i].op_ret == -1) && (replies[i].op_errno == ENODATA))
  165             need_heal = _gf_true;
  166 
  167         if (first_idx == -1) {
  168             first_idx = i;
  169             continue;
  170         }
  171 
  172         if (replies[i].op_ret != replies[first_idx].op_ret)
  173             need_heal = _gf_true;
  174 
  175         if (gf_uuid_compare(replies[i].poststat.ia_gfid,
  176                             replies[first_idx].poststat.ia_gfid))
  177             need_heal = _gf_true;
  178 
  179         if ((replies[i].op_ret == 0) &&
  180             (gf_uuid_is_null(replies[i].poststat.ia_gfid)))
  181             need_heal = _gf_true;
  182     }
  183 
  184     return need_heal;
  185 }
  186 
  187 static int
  188 afr_selfheal_name_type_mismatch_check(xlator_t *this, struct afr_reply *replies,
  189                                       int source, unsigned char *sources,
  190                                       uuid_t pargfid, const char *bname)
  191 {
  192     int i = 0;
  193     int type_idx = -1;
  194     ia_type_t inode_type = IA_INVAL;
  195     ia_type_t inode_type1 = IA_INVAL;
  196     afr_private_t *priv = NULL;
  197 
  198     priv = this->private;
  199 
  200     for (i = 0; i < priv->child_count; i++) {
  201         if (!replies[i].valid || replies[i].op_ret != 0)
  202             continue;
  203 
  204         if (replies[i].poststat.ia_type == IA_INVAL)
  205             continue;
  206 
  207         if (inode_type == IA_INVAL) {
  208             inode_type = replies[i].poststat.ia_type;
  209             type_idx = i;
  210             continue;
  211         }
  212         inode_type1 = replies[i].poststat.ia_type;
  213         if (sources[i] || source == -1) {
  214             if ((sources[type_idx] || source == -1) &&
  215                 (inode_type != inode_type1)) {
  216                 gf_msg(this->name, GF_LOG_WARNING, 0, AFR_MSG_SPLIT_BRAIN,
  217                        "Type mismatch for <gfid:%s>/%s: "
  218                        "%s on %s and %s on %s",
  219                        uuid_utoa(pargfid), bname,
  220                        gf_inode_type_to_str(inode_type1),
  221                        priv->children[i]->name,
  222                        gf_inode_type_to_str(inode_type),
  223                        priv->children[type_idx]->name);
  224                 gf_event(EVENT_AFR_SPLIT_BRAIN,
  225                          "client-pid=%d;"
  226                          "subvol=%s;type=file;"
  227                          "file=<gfid:%s>/%s;count=2;"
  228                          "child-%d=%s;type-%d=%s;child-%d=%s;"
  229                          "type-%d=%s",
  230                          this->ctx->cmd_args.client_pid, this->name,
  231                          uuid_utoa(pargfid), bname, i, priv->children[i]->name,
  232                          i, gf_inode_type_to_str(inode_type1), type_idx,
  233                          priv->children[type_idx]->name, type_idx,
  234                          gf_inode_type_to_str(inode_type));
  235                 return -EIO;
  236             }
  237             inode_type = replies[i].poststat.ia_type;
  238             type_idx = i;
  239         }
  240     }
  241     return 0;
  242 }
  243 
  244 static int
  245 afr_selfheal_name_gfid_mismatch_check(xlator_t *this, struct afr_reply *replies,
  246                                       int source, unsigned char *sources,
  247                                       int *gfid_idx, uuid_t pargfid,
  248                                       const char *bname, inode_t *inode,
  249                                       unsigned char *locked_on, dict_t *xdata)
  250 {
  251     int i = 0;
  252     int gfid_idx_iter = -1;
  253     int ret = -1;
  254     void *gfid = NULL;
  255     void *gfid1 = NULL;
  256     afr_private_t *priv = NULL;
  257 
  258     priv = this->private;
  259 
  260     for (i = 0; i < priv->child_count; i++) {
  261         if (!replies[i].valid || replies[i].op_ret != 0)
  262             continue;
  263 
  264         if (gf_uuid_is_null(replies[i].poststat.ia_gfid))
  265             continue;
  266 
  267         if (!gfid) {
  268             gfid = &replies[i].poststat.ia_gfid;
  269             gfid_idx_iter = i;
  270             continue;
  271         }
  272 
  273         gfid1 = &replies[i].poststat.ia_gfid;
  274         if (sources[i] || source == -1) {
  275             if ((sources[gfid_idx_iter] || source == -1) &&
  276                 gf_uuid_compare(gfid, gfid1)) {
  277                 ret = afr_gfid_split_brain_source(this, replies, inode, pargfid,
  278                                                   bname, gfid_idx_iter, i,
  279                                                   locked_on, gfid_idx, xdata);
  280                 if (!ret && *gfid_idx >= 0) {
  281                     ret = dict_set_sizen_str_sizen(xdata, "gfid-heal-msg",
  282                                                    "GFID split-brain resolved");
  283                     if (ret)
  284                         gf_msg(this->name, GF_LOG_ERROR, 0,
  285                                AFR_MSG_DICT_SET_FAILED,
  286                                "Error setting gfid-"
  287                                "heal-msg dict");
  288                 }
  289                 return ret;
  290             }
  291             gfid = &replies[i].poststat.ia_gfid;
  292             gfid_idx_iter = i;
  293         }
  294     }
  295 
  296     *gfid_idx = gfid_idx_iter;
  297     return 0;
  298 }
  299 
  300 static gf_boolean_t
  301 afr_selfheal_name_source_empty_check(xlator_t *this, struct afr_reply *replies,
  302                                      unsigned char *sources, int source)
  303 {
  304     int i = 0;
  305     afr_private_t *priv = NULL;
  306     gf_boolean_t source_is_empty = _gf_true;
  307 
  308     priv = this->private;
  309 
  310     if (source == -1) {
  311         source_is_empty = _gf_false;
  312         goto out;
  313     }
  314 
  315     for (i = 0; i < priv->child_count; i++) {
  316         if (!sources[i])
  317             continue;
  318 
  319         if (replies[i].op_ret == -1 && replies[i].op_errno == ENOENT)
  320             continue;
  321 
  322         source_is_empty = _gf_false;
  323         break;
  324     }
  325 out:
  326     return source_is_empty;
  327 }
  328 
  329 int
  330 __afr_selfheal_name_do(call_frame_t *frame, xlator_t *this, inode_t *parent,
  331                        uuid_t pargfid, const char *bname, inode_t *inode,
  332                        unsigned char *sources, unsigned char *sinks,
  333                        unsigned char *healed_sinks, int source,
  334                        unsigned char *locked_on, struct afr_reply *replies,
  335                        void *gfid_req, dict_t *xdata)
  336 {
  337     int gfid_idx = -1;
  338     int ret = -1;
  339     void *gfid = NULL;
  340     gf_boolean_t source_is_empty = _gf_true;
  341     gf_boolean_t need_heal = _gf_false;
  342     gf_boolean_t is_gfid_absent = _gf_false;
  343 
  344     need_heal = afr_selfheal_name_need_heal_check(this, replies);
  345     if (!need_heal)
  346         return 0;
  347 
  348     source_is_empty = afr_selfheal_name_source_empty_check(this, replies,
  349                                                            sources, source);
  350     if (source_is_empty) {
  351         ret = __afr_selfheal_name_expunge(this, parent, pargfid, bname, inode,
  352                                           replies);
  353         if (ret == -EIO)
  354             ret = -1;
  355         return ret;
  356     }
  357 
  358     ret = afr_selfheal_name_type_mismatch_check(this, replies, source, sources,
  359                                                 pargfid, bname);
  360     if (ret)
  361         return ret;
  362 
  363     ret = afr_selfheal_name_gfid_mismatch_check(this, replies, source, sources,
  364                                                 &gfid_idx, pargfid, bname,
  365                                                 inode, locked_on, xdata);
  366     if (ret)
  367         return ret;
  368 
  369     if (gfid_idx == -1) {
  370         if (!gfid_req || gf_uuid_is_null(gfid_req))
  371             return -1;
  372         gfid = gfid_req;
  373     } else {
  374         gfid = &replies[gfid_idx].poststat.ia_gfid;
  375         if (source == -1)
  376             /* Either entry split-brain or dirty xattrs are present on parent.*/
  377             source = gfid_idx;
  378     }
  379 
  380     is_gfid_absent = (gfid_idx == -1) ? _gf_true : _gf_false;
  381     ret = __afr_selfheal_assign_gfid(this, parent, pargfid, bname, inode,
  382                                      replies, gfid, locked_on, source, sources,
  383                                      is_gfid_absent, &gfid_idx);
  384     if (ret)
  385         return ret;
  386 
  387     ret = __afr_selfheal_name_impunge(frame, this, parent, pargfid, bname,
  388                                       inode, replies, gfid_idx);
  389     if (ret == -EIO)
  390         ret = -1;
  391 
  392     return ret;
  393 }
  394 
  395 int
  396 __afr_selfheal_name_finalize_source(xlator_t *this, unsigned char *sources,
  397                                     unsigned char *healed_sinks,
  398                                     unsigned char *locked_on, uint64_t *witness)
  399 {
  400     int i = 0;
  401     afr_private_t *priv = NULL;
  402     int source = -1;
  403     int sources_count = 0;
  404 
  405     priv = this->private;
  406 
  407     sources_count = AFR_COUNT(sources, priv->child_count);
  408 
  409     if ((AFR_CMP(locked_on, healed_sinks, priv->child_count) == 0) ||
  410         !sources_count || afr_does_witness_exist(this, witness)) {
  411         memset(sources, 0, sizeof(*sources) * priv->child_count);
  412         afr_mark_active_sinks(this, sources, locked_on, healed_sinks);
  413         return -1;
  414     }
  415 
  416     for (i = 0; i < priv->child_count; i++) {
  417         if (sources[i]) {
  418             source = i;
  419             break;
  420         }
  421     }
  422 
  423     return source;
  424 }
  425 
  426 int
  427 __afr_selfheal_name_prepare(call_frame_t *frame, xlator_t *this,
  428                             inode_t *parent, uuid_t pargfid,
  429                             unsigned char *locked_on, unsigned char *sources,
  430                             unsigned char *sinks, unsigned char *healed_sinks,
  431                             int *source_p)
  432 {
  433     int ret = -1;
  434     int source = -1;
  435     afr_private_t *priv = NULL;
  436     struct afr_reply *replies = NULL;
  437     uint64_t *witness = NULL;
  438 
  439     priv = this->private;
  440 
  441     replies = alloca0(priv->child_count * sizeof(*replies));
  442 
  443     ret = afr_selfheal_unlocked_discover(frame, parent, pargfid, replies);
  444     if (ret)
  445         goto out;
  446 
  447     witness = alloca0(sizeof(*witness) * priv->child_count);
  448     ret = afr_selfheal_find_direction(frame, this, replies,
  449                                       AFR_ENTRY_TRANSACTION, locked_on, sources,
  450                                       sinks, witness, NULL);
  451     if (ret)
  452         goto out;
  453 
  454     /* Initialize the healed_sinks[] array optimistically to
  455        the intersection of to-be-healed (i.e sinks[]) and
  456        the list of servers which are up (i.e locked_on[]).
  457 
  458        As we encounter failures in the healing process, we
  459        will unmark the respective servers in the healed_sinks[]
  460        array.
  461     */
  462     AFR_INTERSECT(healed_sinks, sinks, locked_on, priv->child_count);
  463 
  464     source = __afr_selfheal_name_finalize_source(this, sources, healed_sinks,
  465                                                  locked_on, witness);
  466     if (source < 0) {
  467         /* If source is < 0 (typically split-brain), we perform a
  468            conservative merge of entries rather than erroring out */
  469     }
  470     *source_p = source;
  471 
  472 out:
  473     if (replies)
  474         afr_replies_wipe(replies, priv->child_count);
  475 
  476     return ret;
  477 }
  478 
  479 int
  480 afr_selfheal_name_do(call_frame_t *frame, xlator_t *this, inode_t *parent,
  481                      uuid_t pargfid, const char *bname, void *gfid_req,
  482                      dict_t *xdata)
  483 {
  484     afr_private_t *priv = NULL;
  485     unsigned char *sources = NULL;
  486     unsigned char *sinks = NULL;
  487     unsigned char *healed_sinks = NULL;
  488     unsigned char *locked_on = NULL;
  489     int source = -1;
  490     struct afr_reply *replies = NULL;
  491     int ret = -1;
  492     inode_t *inode = NULL;
  493     dict_t *xattr = NULL;
  494 
  495     xattr = dict_new();
  496     if (!xattr)
  497         return -ENOMEM;
  498 
  499     ret = dict_set_int32_sizen(xattr, GF_GFIDLESS_LOOKUP, 1);
  500     if (ret) {
  501         dict_unref(xattr);
  502         return -1;
  503     }
  504 
  505     priv = this->private;
  506 
  507     locked_on = alloca0(priv->child_count);
  508     sources = alloca0(priv->child_count);
  509     sinks = alloca0(priv->child_count);
  510     healed_sinks = alloca0(priv->child_count);
  511 
  512     replies = alloca0(priv->child_count * sizeof(*replies));
  513 
  514     ret = afr_selfheal_entrylk(frame, this, parent, this->name, bname,
  515                                locked_on);
  516     {
  517         if (ret < priv->child_count) {
  518             ret = -ENOTCONN;
  519             goto unlock;
  520         }
  521 
  522         ret = __afr_selfheal_name_prepare(frame, this, parent, pargfid,
  523                                           locked_on, sources, sinks,
  524                                           healed_sinks, &source);
  525         if (ret)
  526             goto unlock;
  527 
  528         inode = afr_selfheal_unlocked_lookup_on(frame, parent, bname, replies,
  529                                                 locked_on, xattr);
  530         if (!inode) {
  531             ret = -ENOMEM;
  532             goto unlock;
  533         }
  534 
  535         ret = __afr_selfheal_name_do(frame, this, parent, pargfid, bname, inode,
  536                                      sources, sinks, healed_sinks, source,
  537                                      locked_on, replies, gfid_req, xdata);
  538     }
  539 unlock:
  540     afr_selfheal_unentrylk(frame, this, parent, this->name, bname, locked_on,
  541                            NULL);
  542     if (inode)
  543         inode_unref(inode);
  544 
  545     if (replies)
  546         afr_replies_wipe(replies, priv->child_count);
  547     if (xattr)
  548         dict_unref(xattr);
  549 
  550     return ret;
  551 }
  552 
  553 int
  554 afr_selfheal_name_unlocked_inspect(call_frame_t *frame, xlator_t *this,
  555                                    inode_t *parent, uuid_t pargfid,
  556                                    const char *bname, gf_boolean_t *need_heal)
  557 {
  558     afr_private_t *priv = NULL;
  559     int i = 0;
  560     struct afr_reply *replies = NULL;
  561     inode_t *inode = NULL;
  562     int first_idx = -1;
  563     afr_local_t *local = NULL;
  564 
  565     priv = this->private;
  566     local = frame->local;
  567 
  568     replies = alloca0(sizeof(*replies) * priv->child_count);
  569 
  570     inode = afr_selfheal_unlocked_lookup_on(frame, parent, bname, replies,
  571                                             local->child_up, NULL);
  572     if (!inode)
  573         return -ENOMEM;
  574 
  575     for (i = 0; i < priv->child_count; i++) {
  576         if (!replies[i].valid)
  577             continue;
  578 
  579         if ((replies[i].op_ret == -1) && (replies[i].op_errno == ENODATA)) {
  580             *need_heal = _gf_true;
  581             break;
  582         }
  583 
  584         if (first_idx == -1) {
  585             first_idx = i;
  586             continue;
  587         }
  588 
  589         if (replies[i].op_ret != replies[first_idx].op_ret) {
  590             *need_heal = _gf_true;
  591             break;
  592         }
  593 
  594         if (gf_uuid_compare(replies[i].poststat.ia_gfid,
  595                             replies[first_idx].poststat.ia_gfid)) {
  596             *need_heal = _gf_true;
  597             break;
  598         }
  599     }
  600 
  601     if (inode)
  602         inode_unref(inode);
  603     if (replies)
  604         afr_replies_wipe(replies, priv->child_count);
  605     return 0;
  606 }
  607 
  608 int
  609 afr_selfheal_name(xlator_t *this, uuid_t pargfid, const char *bname,
  610                   void *gfid_req, dict_t *xdata)
  611 {
  612     inode_t *parent = NULL;
  613     call_frame_t *frame = NULL;
  614     int ret = -1;
  615     gf_boolean_t need_heal = _gf_false;
  616 
  617     parent = afr_inode_find(this, pargfid);
  618     if (!parent)
  619         goto out;
  620 
  621     frame = afr_frame_create(this, NULL);
  622     if (!frame)
  623         goto out;
  624 
  625     ret = afr_selfheal_name_unlocked_inspect(frame, this, parent, pargfid,
  626                                              bname, &need_heal);
  627     if (ret)
  628         goto out;
  629 
  630     if (need_heal) {
  631         ret = afr_selfheal_name_do(frame, this, parent, pargfid, bname,
  632                                    gfid_req, xdata);
  633         if (ret)
  634             goto out;
  635     }
  636 
  637     ret = 0;
  638 out:
  639     if (parent)
  640         inode_unref(parent);
  641     if (frame)
  642         AFR_STACK_DESTROY(frame);
  643 
  644     return ret;
  645 }