"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.2/xlators/cluster/ec/src/ec-locks.c" (16 Sep 2020, 34538 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 "ec-locks.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2   Copyright (c) 2012-2014 DataLab, s.l. <http://www.datalab.es>
    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 "ec-helpers.h"
   12 #include "ec-common.h"
   13 #include "ec-combine.h"
   14 #include "ec-fops.h"
   15 #include "ec-messages.h"
   16 
   17 #define EC_LOCK_MODE_NONE 0
   18 #define EC_LOCK_MODE_INC 1
   19 #define EC_LOCK_MODE_ALL 2
   20 
   21 int32_t
   22 ec_lock_check(ec_fop_data_t *fop, uintptr_t *mask)
   23 {
   24     ec_t *ec = fop->xl->private;
   25     ec_cbk_data_t *ans = NULL;
   26     ec_cbk_data_t *cbk = NULL;
   27     uintptr_t locked = 0;
   28     int32_t good = 0;
   29     int32_t eagain = 0;
   30     int32_t estale = 0;
   31     int32_t error = -1;
   32 
   33     /* There are some errors that we'll handle in an special way while trying
   34      * to acquire a lock.
   35      *
   36      *   EAGAIN:  If it's found during a parallel non-blocking lock request, we
   37      *            consider that there's contention on the inode, so we consider
   38      *            the acquisition a failure and try again with a sequential
   39      *            blocking lock request. This will ensure that we get a lock on
   40      *            as many bricks as possible (ignoring EAGAIN here would cause
   41      *            unnecessary triggers of self-healing).
   42      *
   43      *            If it's found during a sequential blocking lock request, it's
   44      *            considered an error. Lock will only succeed if there are
   45      *            enough other bricks locked.
   46      *
   47      *   ESTALE:  This can appear during parallel or sequential lock request if
   48      *            the inode has just been unlinked. We consider this error is
   49      *            not recoverable, but we also don't consider it as fatal. So,
   50      *            if it happens during parallel lock, we won't attempt a
   51      *            sequential one unless there are EAGAIN errors on other
   52      *            bricks (and are enough to form a quorum), but if we reach
   53      *            quorum counting the ESTALE bricks, we consider the whole
   54      *            result of the operation is ESTALE instead of EIO.
   55      */
   56 
   57     list_for_each_entry(ans, &fop->cbk_list, list)
   58     {
   59         if (ans->op_ret >= 0) {
   60             if (locked != 0) {
   61                 error = EIO;
   62             }
   63             locked |= ans->mask;
   64             good = ans->count;
   65             cbk = ans;
   66         } else if (ans->op_errno == ESTALE) {
   67             estale += ans->count;
   68         } else if ((ans->op_errno == EAGAIN) &&
   69                    (fop->uint32 != EC_LOCK_MODE_INC)) {
   70             eagain += ans->count;
   71         }
   72     }
   73 
   74     if (error == -1) {
   75         /* If we have enough quorum with succeeded and EAGAIN answers, we
   76          * ignore for now any ESTALE answer. If there are EAGAIN answers,
   77          * we retry with a sequential blocking lock request if needed.
   78          * Otherwise we succeed. */
   79         if ((good + eagain) >= ec->fragments) {
   80             if (eagain == 0) {
   81                 if (fop->answer == NULL) {
   82                     fop->answer = cbk;
   83                 }
   84 
   85                 ec_update_good(fop, locked);
   86 
   87                 error = 0;
   88             } else {
   89                 switch (fop->uint32) {
   90                     case EC_LOCK_MODE_NONE:
   91                         error = EAGAIN;
   92                         break;
   93                     case EC_LOCK_MODE_ALL:
   94                         fop->uint32 = EC_LOCK_MODE_INC;
   95                         break;
   96                     default:
   97                         /* This shouldn't happen because eagain cannot be > 0
   98                          * when fop->uint32 is EC_LOCK_MODE_INC. */
   99                         error = EIO;
  100                         break;
  101                 }
  102             }
  103         } else {
  104             /* We have been unable to find enough candidates that will be able
  105              * to take the lock. If we have quorum on some answer, we return
  106              * it. Otherwise we check if ESTALE answers allow us to reach
  107              * quorum. If so, we return ESTALE. */
  108             if (fop->answer && fop->answer->op_ret < 0) {
  109                 error = fop->answer->op_errno;
  110             } else if ((good + eagain + estale) >= ec->fragments) {
  111                 error = ESTALE;
  112             } else {
  113                 error = EIO;
  114             }
  115         }
  116     }
  117 
  118     *mask = locked;
  119 
  120     return error;
  121 }
  122 
  123 int32_t
  124 ec_lock_unlocked(call_frame_t *frame, void *cookie, xlator_t *this,
  125                  int32_t op_ret, int32_t op_errno, dict_t *xdata)
  126 {
  127     if (op_ret < 0) {
  128         gf_msg(this->name, GF_LOG_WARNING, op_errno, EC_MSG_UNLOCK_FAILED,
  129                "Failed to unlock an entry/inode");
  130     }
  131 
  132     return 0;
  133 }
  134 
  135 int32_t
  136 ec_lock_lk_unlocked(call_frame_t *frame, void *cookie, xlator_t *this,
  137                     int32_t op_ret, int32_t op_errno, struct gf_flock *flock,
  138                     dict_t *xdata)
  139 {
  140     if (op_ret < 0) {
  141         gf_msg(this->name, GF_LOG_WARNING, op_errno, EC_MSG_LK_UNLOCK_FAILED,
  142                "Failed to unlock an lk");
  143     }
  144 
  145     return 0;
  146 }
  147 
  148 /* FOP: entrylk */
  149 
  150 int32_t
  151 ec_entrylk_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
  152                int32_t op_ret, int32_t op_errno, dict_t *xdata)
  153 {
  154     ec_fop_data_t *fop = NULL;
  155     ec_cbk_data_t *cbk = NULL;
  156     int32_t idx = (int32_t)(uintptr_t)cookie;
  157 
  158     VALIDATE_OR_GOTO(this, out);
  159     GF_VALIDATE_OR_GOTO(this->name, frame, out);
  160     GF_VALIDATE_OR_GOTO(this->name, frame->local, out);
  161     GF_VALIDATE_OR_GOTO(this->name, this->private, out);
  162 
  163     fop = frame->local;
  164 
  165     ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, frame,
  166              op_ret, op_errno);
  167 
  168     cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_ENTRYLK, idx, op_ret,
  169                                op_errno);
  170     if (cbk != NULL) {
  171         if (xdata != NULL) {
  172             cbk->xdata = dict_ref(xdata);
  173             if (cbk->xdata == NULL) {
  174                 gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
  175                        "Failed to reference a "
  176                        "dictionary.");
  177 
  178                 goto out;
  179             }
  180         }
  181 
  182         ec_combine(cbk, NULL);
  183     }
  184 
  185 out:
  186     if (fop != NULL) {
  187         ec_complete(fop);
  188     }
  189 
  190     return 0;
  191 }
  192 
  193 void
  194 ec_wind_entrylk(ec_t *ec, ec_fop_data_t *fop, int32_t idx)
  195 {
  196     ec_trace("WIND", fop, "idx=%d", idx);
  197 
  198     STACK_WIND_COOKIE(fop->frame, ec_entrylk_cbk, (void *)(uintptr_t)idx,
  199                       ec->xl_list[idx], ec->xl_list[idx]->fops->entrylk,
  200                       fop->str[0], &fop->loc[0], fop->str[1], fop->entrylk_cmd,
  201                       fop->entrylk_type, fop->xdata);
  202 }
  203 
  204 int32_t
  205 ec_manager_entrylk(ec_fop_data_t *fop, int32_t state)
  206 {
  207     ec_cbk_data_t *cbk;
  208 
  209     switch (state) {
  210         case EC_STATE_INIT:
  211             if (fop->entrylk_cmd == ENTRYLK_LOCK) {
  212                 fop->uint32 = EC_LOCK_MODE_ALL;
  213                 fop->entrylk_cmd = ENTRYLK_LOCK_NB;
  214             }
  215 
  216             /* Fall through */
  217 
  218         case EC_STATE_DISPATCH:
  219             ec_dispatch_all(fop);
  220 
  221             return EC_STATE_PREPARE_ANSWER;
  222 
  223         case EC_STATE_PREPARE_ANSWER:
  224         case -EC_STATE_PREPARE_ANSWER:
  225             if (fop->entrylk_cmd != ENTRYLK_UNLOCK) {
  226                 uintptr_t mask;
  227 
  228                 ec_fop_set_error(fop, ec_lock_check(fop, &mask));
  229                 if (fop->error != 0) {
  230                     if (mask != 0) {
  231                         if (fop->id == GF_FOP_ENTRYLK) {
  232                             ec_entrylk(
  233                                 fop->frame, fop->xl, mask, 1, ec_lock_unlocked,
  234                                 NULL, fop->str[0], &fop->loc[0], fop->str[1],
  235                                 ENTRYLK_UNLOCK, fop->entrylk_type, fop->xdata);
  236                         } else {
  237                             ec_fentrylk(fop->frame, fop->xl, mask, 1,
  238                                         ec_lock_unlocked, NULL, fop->str[0],
  239                                         fop->fd, fop->str[1], ENTRYLK_UNLOCK,
  240                                         fop->entrylk_type, fop->xdata);
  241                         }
  242                     }
  243                     if (fop->error < 0) {
  244                         fop->error = 0;
  245 
  246                         fop->entrylk_cmd = ENTRYLK_LOCK;
  247 
  248                         ec_dispatch_inc(fop);
  249 
  250                         return EC_STATE_PREPARE_ANSWER;
  251                     }
  252                 }
  253             } else {
  254                 ec_fop_prepare_answer(fop, _gf_true);
  255             }
  256 
  257             return EC_STATE_REPORT;
  258 
  259         case EC_STATE_REPORT:
  260             cbk = fop->answer;
  261 
  262             GF_ASSERT(cbk != NULL);
  263 
  264             if (fop->id == GF_FOP_ENTRYLK) {
  265                 if (fop->cbks.entrylk != NULL) {
  266                     fop->cbks.entrylk(fop->req_frame, fop, fop->xl, cbk->op_ret,
  267                                       cbk->op_errno, cbk->xdata);
  268                 }
  269             } else {
  270                 if (fop->cbks.fentrylk != NULL) {
  271                     fop->cbks.fentrylk(fop->req_frame, fop, fop->xl,
  272                                        cbk->op_ret, cbk->op_errno, cbk->xdata);
  273                 }
  274             }
  275 
  276             return EC_STATE_END;
  277 
  278         case -EC_STATE_INIT:
  279         case -EC_STATE_DISPATCH:
  280         case -EC_STATE_REPORT:
  281             GF_ASSERT(fop->error != 0);
  282 
  283             if (fop->id == GF_FOP_ENTRYLK) {
  284                 if (fop->cbks.entrylk != NULL) {
  285                     fop->cbks.entrylk(fop->req_frame, fop, fop->xl, -1,
  286                                       fop->error, NULL);
  287                 }
  288             } else {
  289                 if (fop->cbks.fentrylk != NULL) {
  290                     fop->cbks.fentrylk(fop->req_frame, fop, fop->xl, -1,
  291                                        fop->error, NULL);
  292                 }
  293             }
  294 
  295             return EC_STATE_END;
  296 
  297         default:
  298             gf_msg(fop->xl->name, GF_LOG_ERROR, EINVAL, EC_MSG_UNHANDLED_STATE,
  299                    "Unhandled state %d for %s", state, ec_fop_name(fop->id));
  300 
  301             return EC_STATE_END;
  302     }
  303 }
  304 
  305 void
  306 ec_entrylk(call_frame_t *frame, xlator_t *this, uintptr_t target,
  307            uint32_t fop_flags, fop_entrylk_cbk_t func, void *data,
  308            const char *volume, loc_t *loc, const char *basename,
  309            entrylk_cmd cmd, entrylk_type type, dict_t *xdata)
  310 {
  311     ec_cbk_t callback = {.entrylk = func};
  312     ec_fop_data_t *fop = NULL;
  313     int32_t error = ENOMEM;
  314 
  315     gf_msg_trace("ec", 0, "EC(ENTRYLK) %p", frame);
  316 
  317     GF_VALIDATE_OR_GOTO(this->name, frame, out);
  318     GF_VALIDATE_OR_GOTO(this->name, this->private, out);
  319 
  320     fop = ec_fop_data_allocate(frame, this, GF_FOP_ENTRYLK, 0, target,
  321                                fop_flags, ec_wind_entrylk, ec_manager_entrylk,
  322                                callback, data);
  323     if (fop == NULL) {
  324         goto out;
  325     }
  326 
  327     fop->entrylk_cmd = cmd;
  328     fop->entrylk_type = type;
  329 
  330     if (volume != NULL) {
  331         fop->str[0] = gf_strdup(volume);
  332         if (fop->str[0] == NULL) {
  333             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_NO_MEMORY,
  334                    "Failed to duplicate a string.");
  335 
  336             goto out;
  337         }
  338     }
  339     if (loc != NULL) {
  340         if (loc_copy(&fop->loc[0], loc) != 0) {
  341             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_LOC_COPY_FAIL,
  342                    "Failed to copy a location.");
  343 
  344             goto out;
  345         }
  346     }
  347     if (basename != NULL) {
  348         fop->str[1] = gf_strdup(basename);
  349         if (fop->str[1] == NULL) {
  350             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_NO_MEMORY,
  351                    "Failed to duplicate a string.");
  352 
  353             goto out;
  354         }
  355     }
  356     if (xdata != NULL) {
  357         fop->xdata = dict_ref(xdata);
  358         if (fop->xdata == NULL) {
  359             gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
  360                    "Failed to reference a "
  361                    "dictionary.");
  362 
  363             goto out;
  364         }
  365     }
  366 
  367     error = 0;
  368 
  369 out:
  370     if (fop != NULL) {
  371         ec_manager(fop, error);
  372     } else {
  373         func(frame, NULL, this, -1, error, NULL);
  374     }
  375 }
  376 
  377 /* FOP: fentrylk */
  378 
  379 int32_t
  380 ec_fentrylk_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
  381                 int32_t op_ret, int32_t op_errno, dict_t *xdata)
  382 {
  383     ec_fop_data_t *fop = NULL;
  384     ec_cbk_data_t *cbk = NULL;
  385     int32_t idx = (int32_t)(uintptr_t)cookie;
  386 
  387     VALIDATE_OR_GOTO(this, out);
  388     GF_VALIDATE_OR_GOTO(this->name, frame, out);
  389     GF_VALIDATE_OR_GOTO(this->name, frame->local, out);
  390     GF_VALIDATE_OR_GOTO(this->name, this->private, out);
  391 
  392     fop = frame->local;
  393 
  394     ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, frame,
  395              op_ret, op_errno);
  396 
  397     cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_FENTRYLK, idx, op_ret,
  398                                op_errno);
  399     if (cbk != NULL) {
  400         if (xdata != NULL) {
  401             cbk->xdata = dict_ref(xdata);
  402             if (cbk->xdata == NULL) {
  403                 gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
  404                        "Failed to reference a "
  405                        "dictionary.");
  406 
  407                 goto out;
  408             }
  409         }
  410 
  411         ec_combine(cbk, NULL);
  412     }
  413 
  414 out:
  415     if (fop != NULL) {
  416         ec_complete(fop);
  417     }
  418 
  419     return 0;
  420 }
  421 
  422 void
  423 ec_wind_fentrylk(ec_t *ec, ec_fop_data_t *fop, int32_t idx)
  424 {
  425     ec_trace("WIND", fop, "idx=%d", idx);
  426 
  427     STACK_WIND_COOKIE(fop->frame, ec_fentrylk_cbk, (void *)(uintptr_t)idx,
  428                       ec->xl_list[idx], ec->xl_list[idx]->fops->fentrylk,
  429                       fop->str[0], fop->fd, fop->str[1], fop->entrylk_cmd,
  430                       fop->entrylk_type, fop->xdata);
  431 }
  432 
  433 void
  434 ec_fentrylk(call_frame_t *frame, xlator_t *this, uintptr_t target,
  435             uint32_t fop_flags, fop_fentrylk_cbk_t func, void *data,
  436             const char *volume, fd_t *fd, const char *basename, entrylk_cmd cmd,
  437             entrylk_type type, dict_t *xdata)
  438 {
  439     ec_cbk_t callback = {.fentrylk = func};
  440     ec_fop_data_t *fop = NULL;
  441     int32_t error = ENOMEM;
  442 
  443     gf_msg_trace("ec", 0, "EC(FENTRYLK) %p", frame);
  444 
  445     GF_VALIDATE_OR_GOTO(this->name, frame, out);
  446     GF_VALIDATE_OR_GOTO(this->name, this->private, out);
  447 
  448     fop = ec_fop_data_allocate(frame, this, GF_FOP_FENTRYLK, 0, target,
  449                                fop_flags, ec_wind_fentrylk, ec_manager_entrylk,
  450                                callback, data);
  451     if (fop == NULL) {
  452         goto out;
  453     }
  454 
  455     fop->use_fd = 1;
  456 
  457     fop->entrylk_cmd = cmd;
  458     fop->entrylk_type = type;
  459 
  460     if (volume != NULL) {
  461         fop->str[0] = gf_strdup(volume);
  462         if (fop->str[0] == NULL) {
  463             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_NO_MEMORY,
  464                    "Failed to duplicate a string.");
  465 
  466             goto out;
  467         }
  468     }
  469     if (fd != NULL) {
  470         fop->fd = fd_ref(fd);
  471         if (fop->fd == NULL) {
  472             gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_FILE_DESC_REF_FAIL,
  473                    "Failed to reference a "
  474                    "file descriptor.");
  475 
  476             goto out;
  477         }
  478     }
  479     if (basename != NULL) {
  480         fop->str[1] = gf_strdup(basename);
  481         if (fop->str[1] == NULL) {
  482             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_NO_MEMORY,
  483                    "Failed to duplicate a string.");
  484 
  485             goto out;
  486         }
  487     }
  488     if (xdata != NULL) {
  489         fop->xdata = dict_ref(xdata);
  490         if (fop->xdata == NULL) {
  491             gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
  492                    "Failed to reference a "
  493                    "dictionary.");
  494 
  495             goto out;
  496         }
  497     }
  498 
  499     error = 0;
  500 
  501 out:
  502     if (fop != NULL) {
  503         ec_manager(fop, error);
  504     } else {
  505         func(frame, NULL, this, -1, error, NULL);
  506     }
  507 }
  508 
  509 /* FOP: inodelk */
  510 
  511 int32_t
  512 ec_inodelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
  513                int32_t op_ret, int32_t op_errno, dict_t *xdata)
  514 {
  515     ec_fop_data_t *fop = NULL;
  516     ec_cbk_data_t *cbk = NULL;
  517     int32_t idx = (int32_t)(uintptr_t)cookie;
  518 
  519     VALIDATE_OR_GOTO(this, out);
  520     GF_VALIDATE_OR_GOTO(this->name, frame, out);
  521     GF_VALIDATE_OR_GOTO(this->name, frame->local, out);
  522     GF_VALIDATE_OR_GOTO(this->name, this->private, out);
  523 
  524     fop = frame->local;
  525 
  526     ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, frame,
  527              op_ret, op_errno);
  528 
  529     cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_INODELK, idx, op_ret,
  530                                op_errno);
  531     if (cbk != NULL) {
  532         if (xdata != NULL) {
  533             cbk->xdata = dict_ref(xdata);
  534             if (cbk->xdata == NULL) {
  535                 gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
  536                        "Failed to reference a "
  537                        "dictionary.");
  538 
  539                 goto out;
  540             }
  541         }
  542 
  543         ec_combine(cbk, NULL);
  544     }
  545 
  546 out:
  547     if (fop != NULL) {
  548         ec_complete(fop);
  549     }
  550 
  551     return 0;
  552 }
  553 
  554 void
  555 ec_wind_inodelk(ec_t *ec, ec_fop_data_t *fop, int32_t idx)
  556 {
  557     ec_trace("WIND", fop, "idx=%d", idx);
  558 
  559     STACK_WIND_COOKIE(fop->frame, ec_inodelk_cbk, (void *)(uintptr_t)idx,
  560                       ec->xl_list[idx], ec->xl_list[idx]->fops->inodelk,
  561                       fop->str[0], &fop->loc[0], fop->int32, &fop->flock,
  562                       fop->xdata);
  563 }
  564 
  565 int32_t
  566 ec_manager_inodelk(ec_fop_data_t *fop, int32_t state)
  567 {
  568     ec_cbk_data_t *cbk;
  569 
  570     switch (state) {
  571         case EC_STATE_INIT:
  572             fop->flock.l_len += ec_adjust_offset_down(
  573                 fop->xl->private, &fop->flock.l_start, _gf_true);
  574             ec_adjust_offset_up(fop->xl->private, &fop->flock.l_len, _gf_true);
  575             if ((fop->int32 == F_SETLKW) && (fop->flock.l_type != F_UNLCK)) {
  576                 fop->uint32 = EC_LOCK_MODE_ALL;
  577                 fop->int32 = F_SETLK;
  578             }
  579 
  580             /* Fall through */
  581 
  582         case EC_STATE_DISPATCH:
  583             ec_dispatch_all(fop);
  584 
  585             return EC_STATE_PREPARE_ANSWER;
  586 
  587         case EC_STATE_PREPARE_ANSWER:
  588         case -EC_STATE_PREPARE_ANSWER:
  589             if (fop->flock.l_type != F_UNLCK) {
  590                 uintptr_t mask;
  591 
  592                 ec_fop_set_error(fop, ec_lock_check(fop, &mask));
  593                 if (fop->error != 0) {
  594                     if (mask != 0) {
  595                         ec_t *ec = fop->xl->private;
  596                         struct gf_flock flock;
  597 
  598                         flock.l_type = F_UNLCK;
  599                         flock.l_whence = fop->flock.l_whence;
  600                         flock.l_start = fop->flock.l_start * ec->fragments;
  601                         flock.l_len = fop->flock.l_len * ec->fragments;
  602                         flock.l_pid = 0;
  603                         flock.l_owner.len = 0;
  604 
  605                         if (fop->id == GF_FOP_INODELK) {
  606                             ec_inodelk(fop->frame, fop->xl,
  607                                        &fop->frame->root->lk_owner, mask, 1,
  608                                        ec_lock_unlocked, NULL, fop->str[0],
  609                                        &fop->loc[0], F_SETLK, &flock,
  610                                        fop->xdata);
  611                         } else {
  612                             ec_finodelk(fop->frame, fop->xl,
  613                                         &fop->frame->root->lk_owner, mask, 1,
  614                                         ec_lock_unlocked, NULL, fop->str[0],
  615                                         fop->fd, F_SETLK, &flock, fop->xdata);
  616                         }
  617                     }
  618                     if (fop->error < 0) {
  619                         fop->error = 0;
  620 
  621                         fop->int32 = F_SETLKW;
  622 
  623                         ec_dispatch_inc(fop);
  624 
  625                         return EC_STATE_PREPARE_ANSWER;
  626                     }
  627                 }
  628             } else {
  629                 ec_fop_prepare_answer(fop, _gf_true);
  630             }
  631 
  632             return EC_STATE_REPORT;
  633 
  634         case EC_STATE_REPORT:
  635             cbk = fop->answer;
  636 
  637             GF_ASSERT(cbk != NULL);
  638 
  639             if (fop->id == GF_FOP_INODELK) {
  640                 if (fop->cbks.inodelk != NULL) {
  641                     fop->cbks.inodelk(fop->req_frame, fop, fop->xl, cbk->op_ret,
  642                                       cbk->op_errno, cbk->xdata);
  643                 }
  644             } else {
  645                 if (fop->cbks.finodelk != NULL) {
  646                     fop->cbks.finodelk(fop->req_frame, fop, fop->xl,
  647                                        cbk->op_ret, cbk->op_errno, cbk->xdata);
  648                 }
  649             }
  650 
  651             return EC_STATE_END;
  652 
  653         case -EC_STATE_INIT:
  654         case -EC_STATE_DISPATCH:
  655         case -EC_STATE_REPORT:
  656             GF_ASSERT(fop->error != 0);
  657 
  658             if (fop->id == GF_FOP_INODELK) {
  659                 if (fop->cbks.inodelk != NULL) {
  660                     fop->cbks.inodelk(fop->req_frame, fop, fop->xl, -1,
  661                                       fop->error, NULL);
  662                 }
  663             } else {
  664                 if (fop->cbks.finodelk != NULL) {
  665                     fop->cbks.finodelk(fop->req_frame, fop, fop->xl, -1,
  666                                        fop->error, NULL);
  667                 }
  668             }
  669 
  670             return EC_STATE_END;
  671 
  672         default:
  673             gf_msg(fop->xl->name, GF_LOG_ERROR, EINVAL, EC_MSG_UNHANDLED_STATE,
  674                    "Unhandled state %d for %s", state, ec_fop_name(fop->id));
  675 
  676             return EC_STATE_END;
  677     }
  678 }
  679 
  680 void
  681 ec_inodelk(call_frame_t *frame, xlator_t *this, gf_lkowner_t *owner,
  682            uintptr_t target, uint32_t fop_flags, fop_inodelk_cbk_t func,
  683            void *data, const char *volume, loc_t *loc, int32_t cmd,
  684            struct gf_flock *flock, dict_t *xdata)
  685 {
  686     ec_cbk_t callback = {.inodelk = func};
  687     ec_fop_data_t *fop = NULL;
  688     int32_t error = ENOMEM;
  689 
  690     gf_msg_trace("ec", 0, "EC(INODELK) %p", frame);
  691 
  692     VALIDATE_OR_GOTO(this, out);
  693     GF_VALIDATE_OR_GOTO(this->name, frame, out);
  694     GF_VALIDATE_OR_GOTO(this->name, this->private, out);
  695 
  696     fop = ec_fop_data_allocate(frame, this, GF_FOP_INODELK, 0, target,
  697                                fop_flags, ec_wind_inodelk, ec_manager_inodelk,
  698                                callback, data);
  699     if (fop == NULL) {
  700         goto out;
  701     }
  702 
  703     fop->int32 = cmd;
  704     ec_owner_copy(fop->frame, owner);
  705 
  706     if (volume != NULL) {
  707         fop->str[0] = gf_strdup(volume);
  708         if (fop->str[0] == NULL) {
  709             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_NO_MEMORY,
  710                    "Failed to duplicate a string.");
  711 
  712             goto out;
  713         }
  714     }
  715     if (loc != NULL) {
  716         if (loc_copy(&fop->loc[0], loc) != 0) {
  717             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_LOC_COPY_FAIL,
  718                    "Failed to copy a location.");
  719 
  720             goto out;
  721         }
  722     }
  723     if (flock != NULL) {
  724         fop->flock.l_type = flock->l_type;
  725         fop->flock.l_whence = flock->l_whence;
  726         fop->flock.l_start = flock->l_start;
  727         fop->flock.l_len = flock->l_len;
  728         fop->flock.l_pid = flock->l_pid;
  729         fop->flock.l_owner.len = flock->l_owner.len;
  730         if (flock->l_owner.len > 0) {
  731             memcpy(fop->flock.l_owner.data, flock->l_owner.data,
  732                    flock->l_owner.len);
  733         }
  734     }
  735     if (xdata != NULL) {
  736         fop->xdata = dict_ref(xdata);
  737         if (fop->xdata == NULL) {
  738             gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
  739                    "Failed to reference a "
  740                    "dictionary.");
  741 
  742             goto out;
  743         }
  744     }
  745 
  746     error = 0;
  747 
  748 out:
  749     if (fop != NULL) {
  750         ec_manager(fop, error);
  751     } else {
  752         func(frame, NULL, this, -1, error, NULL);
  753     }
  754 }
  755 
  756 /* FOP: finodelk */
  757 
  758 int32_t
  759 ec_finodelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
  760                 int32_t op_ret, int32_t op_errno, dict_t *xdata)
  761 {
  762     ec_fop_data_t *fop = NULL;
  763     ec_cbk_data_t *cbk = NULL;
  764     int32_t idx = (int32_t)(uintptr_t)cookie;
  765 
  766     VALIDATE_OR_GOTO(this, out);
  767     GF_VALIDATE_OR_GOTO(this->name, frame, out);
  768     GF_VALIDATE_OR_GOTO(this->name, frame->local, out);
  769     GF_VALIDATE_OR_GOTO(this->name, this->private, out);
  770 
  771     fop = frame->local;
  772 
  773     ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, frame,
  774              op_ret, op_errno);
  775 
  776     cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_FINODELK, idx, op_ret,
  777                                op_errno);
  778     if (cbk != NULL) {
  779         if (xdata != NULL) {
  780             cbk->xdata = dict_ref(xdata);
  781             if (cbk->xdata == NULL) {
  782                 gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
  783                        "Failed to reference a "
  784                        "dictionary.");
  785 
  786                 goto out;
  787             }
  788         }
  789 
  790         ec_combine(cbk, NULL);
  791     }
  792 
  793 out:
  794     if (fop != NULL) {
  795         ec_complete(fop);
  796     }
  797 
  798     return 0;
  799 }
  800 
  801 void
  802 ec_wind_finodelk(ec_t *ec, ec_fop_data_t *fop, int32_t idx)
  803 {
  804     ec_trace("WIND", fop, "idx=%d", idx);
  805 
  806     STACK_WIND_COOKIE(fop->frame, ec_finodelk_cbk, (void *)(uintptr_t)idx,
  807                       ec->xl_list[idx], ec->xl_list[idx]->fops->finodelk,
  808                       fop->str[0], fop->fd, fop->int32, &fop->flock,
  809                       fop->xdata);
  810 }
  811 
  812 void
  813 ec_finodelk(call_frame_t *frame, xlator_t *this, gf_lkowner_t *owner,
  814             uintptr_t target, uint32_t fop_flags, fop_finodelk_cbk_t func,
  815             void *data, const char *volume, fd_t *fd, int32_t cmd,
  816             struct gf_flock *flock, dict_t *xdata)
  817 {
  818     ec_cbk_t callback = {.finodelk = func};
  819     ec_fop_data_t *fop = NULL;
  820     int32_t error = ENOMEM;
  821 
  822     gf_msg_trace("ec", 0, "EC(FINODELK) %p", frame);
  823 
  824     VALIDATE_OR_GOTO(this, out);
  825     GF_VALIDATE_OR_GOTO(this->name, frame, out);
  826     GF_VALIDATE_OR_GOTO(this->name, this->private, out);
  827 
  828     fop = ec_fop_data_allocate(frame, this, GF_FOP_FINODELK, 0, target,
  829                                fop_flags, ec_wind_finodelk, ec_manager_inodelk,
  830                                callback, data);
  831     if (fop == NULL) {
  832         goto out;
  833     }
  834 
  835     fop->use_fd = 1;
  836 
  837     fop->int32 = cmd;
  838     ec_owner_copy(fop->frame, owner);
  839 
  840     if (volume != NULL) {
  841         fop->str[0] = gf_strdup(volume);
  842         if (fop->str[0] == NULL) {
  843             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_NO_MEMORY,
  844                    "Failed to duplicate a string.");
  845 
  846             goto out;
  847         }
  848     }
  849     if (fd != NULL) {
  850         fop->fd = fd_ref(fd);
  851         if (fop->fd == NULL) {
  852             gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
  853                    "Failed to reference a "
  854                    "file descriptor.");
  855 
  856             goto out;
  857         }
  858     }
  859     if (flock != NULL) {
  860         fop->flock.l_type = flock->l_type;
  861         fop->flock.l_whence = flock->l_whence;
  862         fop->flock.l_start = flock->l_start;
  863         fop->flock.l_len = flock->l_len;
  864         fop->flock.l_pid = flock->l_pid;
  865         fop->flock.l_owner.len = flock->l_owner.len;
  866         if (flock->l_owner.len > 0) {
  867             memcpy(fop->flock.l_owner.data, flock->l_owner.data,
  868                    flock->l_owner.len);
  869         }
  870     }
  871     if (xdata != NULL) {
  872         fop->xdata = dict_ref(xdata);
  873         if (fop->xdata == NULL) {
  874             gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
  875                    "Failed to reference a "
  876                    "dictionary.");
  877 
  878             goto out;
  879         }
  880     }
  881 
  882     error = 0;
  883 
  884 out:
  885     if (fop != NULL) {
  886         ec_manager(fop, error);
  887     } else {
  888         func(frame, NULL, this, -1, error, NULL);
  889     }
  890 }
  891 
  892 /* FOP: lk */
  893 
  894 int32_t
  895 ec_combine_lk(ec_fop_data_t *fop, ec_cbk_data_t *dst, ec_cbk_data_t *src)
  896 {
  897     if (!ec_flock_compare(&dst->flock, &src->flock)) {
  898         gf_msg(fop->xl->name, GF_LOG_NOTICE, 0, EC_MSG_LOCK_MISMATCH,
  899                "Mismatching lock in "
  900                "answers of 'GF_FOP_LK'");
  901 
  902         return 0;
  903     }
  904 
  905     return 1;
  906 }
  907 
  908 int32_t
  909 ec_lk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
  910           int32_t op_errno, struct gf_flock *flock, dict_t *xdata)
  911 {
  912     ec_fop_data_t *fop = NULL;
  913     ec_cbk_data_t *cbk = NULL;
  914     int32_t idx = (int32_t)(uintptr_t)cookie;
  915 
  916     VALIDATE_OR_GOTO(this, out);
  917     GF_VALIDATE_OR_GOTO(this->name, frame, out);
  918     GF_VALIDATE_OR_GOTO(this->name, frame->local, out);
  919     GF_VALIDATE_OR_GOTO(this->name, this->private, out);
  920 
  921     fop = frame->local;
  922 
  923     ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, frame,
  924              op_ret, op_errno);
  925 
  926     cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_LK, idx, op_ret,
  927                                op_errno);
  928     if (cbk != NULL) {
  929         if (op_ret >= 0) {
  930             if (flock != NULL) {
  931                 cbk->flock.l_type = flock->l_type;
  932                 cbk->flock.l_whence = flock->l_whence;
  933                 cbk->flock.l_start = flock->l_start;
  934                 cbk->flock.l_len = flock->l_len;
  935                 cbk->flock.l_pid = flock->l_pid;
  936                 cbk->flock.l_owner.len = flock->l_owner.len;
  937                 if (flock->l_owner.len > 0) {
  938                     memcpy(cbk->flock.l_owner.data, flock->l_owner.data,
  939                            flock->l_owner.len);
  940                 }
  941             }
  942         }
  943         if (xdata != NULL) {
  944             cbk->xdata = dict_ref(xdata);
  945             if (cbk->xdata == NULL) {
  946                 gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
  947                        "Failed to reference a "
  948                        "dictionary.");
  949 
  950                 goto out;
  951             }
  952         }
  953 
  954         ec_combine(cbk, ec_combine_lk);
  955     }
  956 
  957 out:
  958     if (fop != NULL) {
  959         ec_complete(fop);
  960     }
  961 
  962     return 0;
  963 }
  964 
  965 void
  966 ec_wind_lk(ec_t *ec, ec_fop_data_t *fop, int32_t idx)
  967 {
  968     ec_trace("WIND", fop, "idx=%d", idx);
  969 
  970     STACK_WIND_COOKIE(fop->frame, ec_lk_cbk, (void *)(uintptr_t)idx,
  971                       ec->xl_list[idx], ec->xl_list[idx]->fops->lk, fop->fd,
  972                       fop->int32, &fop->flock, fop->xdata);
  973 }
  974 
  975 int32_t
  976 ec_manager_lk(ec_fop_data_t *fop, int32_t state)
  977 {
  978     ec_cbk_data_t *cbk;
  979 
  980     switch (state) {
  981         case EC_STATE_INIT:
  982             if ((fop->int32 == F_SETLKW) && (fop->flock.l_type != F_UNLCK)) {
  983                 fop->uint32 = EC_LOCK_MODE_ALL;
  984                 fop->int32 = F_SETLK;
  985             }
  986 
  987             /* Fall through */
  988 
  989         case EC_STATE_DISPATCH:
  990             ec_dispatch_all(fop);
  991 
  992             return EC_STATE_PREPARE_ANSWER;
  993 
  994         case EC_STATE_PREPARE_ANSWER:
  995         case -EC_STATE_PREPARE_ANSWER:
  996             if (fop->flock.l_type != F_UNLCK) {
  997                 uintptr_t mask;
  998 
  999                 ec_fop_set_error(fop, ec_lock_check(fop, &mask));
 1000                 if (fop->error != 0) {
 1001                     if (mask != 0) {
 1002                         struct gf_flock flock = {0};
 1003 
 1004                         flock.l_type = F_UNLCK;
 1005                         flock.l_whence = fop->flock.l_whence;
 1006                         flock.l_start = fop->flock.l_start;
 1007                         flock.l_len = fop->flock.l_len;
 1008                         flock.l_pid = fop->flock.l_pid;
 1009                         lk_owner_copy(&flock.l_owner, &fop->flock.l_owner);
 1010 
 1011                         ec_lk(fop->frame, fop->xl, mask, 1, ec_lock_lk_unlocked,
 1012                               NULL, fop->fd, F_SETLK, &flock, fop->xdata);
 1013                     }
 1014 
 1015                     if (fop->error < 0) {
 1016                         fop->error = 0;
 1017 
 1018                         fop->int32 = F_SETLKW;
 1019 
 1020                         ec_dispatch_inc(fop);
 1021 
 1022                         return EC_STATE_PREPARE_ANSWER;
 1023                     }
 1024                 }
 1025             } else {
 1026                 ec_fop_prepare_answer(fop, _gf_true);
 1027             }
 1028 
 1029             return EC_STATE_REPORT;
 1030 
 1031         case EC_STATE_REPORT:
 1032             cbk = fop->answer;
 1033 
 1034             GF_ASSERT(cbk != NULL);
 1035 
 1036             if (fop->cbks.lk != NULL) {
 1037                 fop->cbks.lk(fop->req_frame, fop, fop->xl, cbk->op_ret,
 1038                              cbk->op_errno, &cbk->flock, cbk->xdata);
 1039             }
 1040 
 1041             return EC_STATE_END;
 1042 
 1043         case -EC_STATE_INIT:
 1044         case -EC_STATE_DISPATCH:
 1045         case -EC_STATE_REPORT:
 1046             GF_ASSERT(fop->error != 0);
 1047 
 1048             if (fop->cbks.lk != NULL) {
 1049                 fop->cbks.lk(fop->req_frame, fop, fop->xl, -1, fop->error, NULL,
 1050                              NULL);
 1051             }
 1052 
 1053             return EC_STATE_END;
 1054 
 1055         default:
 1056             gf_msg(fop->xl->name, GF_LOG_ERROR, EINVAL, EC_MSG_UNHANDLED_STATE,
 1057                    "Unhandled state %d for %s", state, ec_fop_name(fop->id));
 1058 
 1059             return EC_STATE_END;
 1060     }
 1061 }
 1062 
 1063 void
 1064 ec_lk(call_frame_t *frame, xlator_t *this, uintptr_t target, uint32_t fop_flags,
 1065       fop_lk_cbk_t func, void *data, fd_t *fd, int32_t cmd,
 1066       struct gf_flock *flock, dict_t *xdata)
 1067 {
 1068     ec_cbk_t callback = {.lk = func};
 1069     ec_fop_data_t *fop = NULL;
 1070     int32_t error = ENOMEM;
 1071 
 1072     gf_msg_trace("ec", 0, "EC(LK) %p", frame);
 1073 
 1074     GF_VALIDATE_OR_GOTO(this->name, frame, out);
 1075     GF_VALIDATE_OR_GOTO(this->name, this->private, out);
 1076 
 1077     fop = ec_fop_data_allocate(frame, this, GF_FOP_LK, 0, target, fop_flags,
 1078                                ec_wind_lk, ec_manager_lk, callback, data);
 1079     if (fop == NULL) {
 1080         goto out;
 1081     }
 1082 
 1083     fop->use_fd = 1;
 1084 
 1085     fop->int32 = cmd;
 1086 
 1087     if (fd != NULL) {
 1088         fop->fd = fd_ref(fd);
 1089         if (fop->fd == NULL) {
 1090             gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_FILE_DESC_REF_FAIL,
 1091                    "Failed to reference a "
 1092                    "file descriptor.");
 1093 
 1094             goto out;
 1095         }
 1096     }
 1097     if (flock != NULL) {
 1098         fop->flock.l_type = flock->l_type;
 1099         fop->flock.l_whence = flock->l_whence;
 1100         fop->flock.l_start = flock->l_start;
 1101         fop->flock.l_len = flock->l_len;
 1102         fop->flock.l_pid = flock->l_pid;
 1103         fop->flock.l_owner.len = flock->l_owner.len;
 1104         if (flock->l_owner.len > 0) {
 1105             memcpy(fop->flock.l_owner.data, flock->l_owner.data,
 1106                    flock->l_owner.len);
 1107         }
 1108     }
 1109     if (xdata != NULL) {
 1110         fop->xdata = dict_ref(xdata);
 1111         if (fop->xdata == NULL) {
 1112             gf_msg(this->name, GF_LOG_ERROR, 0, EC_MSG_DICT_REF_FAIL,
 1113                    "Failed to reference a "
 1114                    "dictionary.");
 1115 
 1116             goto out;
 1117         }
 1118     }
 1119 
 1120     error = 0;
 1121 
 1122 out:
 1123     if (fop != NULL) {
 1124         ec_manager(fop, error);
 1125     } else {
 1126         func(frame, NULL, this, -1, error, NULL, NULL);
 1127     }
 1128 }