"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.2/xlators/features/leases/src/leases-internal.c" (16 Sep 2020, 42593 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 "leases-internal.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2    Copyright (c) 2015-2016 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 #ifndef _CONFIG_H
   12 #define _CONFIG_H
   13 #include "config.h"
   14 #endif
   15 
   16 #include "leases.h"
   17 
   18 /* Mutex locks used in this xlator and their order of acquisition:
   19  * Check lease conflict:
   20  *         lease_ctx lock
   21  *                 add_timer => internal timer locks
   22  *         lease_ctx unlock
   23  *
   24  * Add/remove lease:
   25  *         lease_ctx lock
   26  *                 add_timer => internal timer locks
   27  *                 OR
   28  *                 priv lock => Adding/removing to/from the cleanup client list
   29  *                 priv unlock
   30  *         lease_ctx unlock
   31  *
   32  * Timer thread:
   33  *         Timer internal lock
   34  *                 priv lock => By timer handler
   35  *                 priv unlock
   36  *         Timer internal unlock
   37  *
   38  * Expired recall cleanup thread:
   39  *         priv lock
   40  *                 priv condwait
   41  *         priv unlock
   42  *         lease_ctx lock
   43  *                 priv lock
   44  *                 priv unlock
   45  *         lease_ctx unlock
   46  */
   47 
   48 /*
   49  * Check if lease_lk is enabled
   50  * Return Value:
   51  * _gf_true  - lease lock option enabled
   52  * _gf_false - lease lock option disabled
   53  */
   54 gf_boolean_t
   55 is_leases_enabled(xlator_t *this)
   56 {
   57     leases_private_t *priv = NULL;
   58     gf_boolean_t is_enabled = _gf_false;
   59 
   60     GF_VALIDATE_OR_GOTO("leases", this, out);
   61 
   62     if (this->private) {
   63         priv = (leases_private_t *)this->private;
   64         is_enabled = priv->leases_enabled;
   65     }
   66 out:
   67     return is_enabled;
   68 }
   69 
   70 /*
   71  * Get the recall_leaselk_timeout
   72  * Return Value:
   73  * timeout value(in seconds) set as an option to this xlator.
   74  * -1 error case
   75  */
   76 static int32_t
   77 get_recall_lease_timeout(xlator_t *this)
   78 {
   79     leases_private_t *priv = NULL;
   80     int32_t timeout = -1;
   81 
   82     GF_VALIDATE_OR_GOTO("leases", this, out);
   83 
   84     if (this->private) {
   85         priv = (leases_private_t *)this->private;
   86         timeout = priv->recall_lease_timeout;
   87     }
   88 out:
   89     return timeout;
   90 }
   91 
   92 static void
   93 __dump_leases_info(xlator_t *this, lease_inode_ctx_t *lease_ctx)
   94 {
   95     lease_id_entry_t *lease_entry = NULL;
   96     lease_id_entry_t *tmp = NULL;
   97 
   98     GF_VALIDATE_OR_GOTO("leases", this, out);
   99     GF_VALIDATE_OR_GOTO("leases", lease_ctx, out);
  100 
  101     gf_msg_debug(this->name, 0,
  102                  "Lease held on this inode, lease_type: %d,"
  103                  " lease_cnt:%" PRIu64
  104                  ", RD lease:%d, RW lease:%d, "
  105                  "openfd cnt:%" PRIu64,
  106                  lease_ctx->lease_type, lease_ctx->lease_cnt,
  107                  lease_ctx->lease_type_cnt[GF_RD_LEASE],
  108                  lease_ctx->lease_type_cnt[GF_RW_LEASE], lease_ctx->openfd_cnt);
  109 
  110     list_for_each_entry_safe(lease_entry, tmp, &lease_ctx->lease_id_list,
  111                              lease_id_list)
  112     {
  113         gf_msg_debug(this->name, 0,
  114                      "Leases held by client: %s, lease "
  115                      "ID:%s, RD lease:%d, RW lease:%d, lease_type: %d, "
  116                      "lease_cnt:%" PRIu64,
  117                      lease_entry->client_uid, lease_entry->lease_id,
  118                      lease_entry->lease_type_cnt[GF_RD_LEASE],
  119                      lease_entry->lease_type_cnt[GF_RW_LEASE],
  120                      lease_entry->lease_type, lease_entry->lease_cnt);
  121     }
  122 out:
  123     return;
  124 }
  125 
  126 static int
  127 __lease_ctx_set(inode_t *inode, xlator_t *this)
  128 {
  129     lease_inode_ctx_t *inode_ctx = NULL;
  130     int ret = -1;
  131     uint64_t ctx = 0;
  132 
  133     GF_VALIDATE_OR_GOTO("leases", inode, out);
  134     GF_VALIDATE_OR_GOTO("leases", this, out);
  135 
  136     ret = __inode_ctx_get(inode, this, &ctx);
  137     if (!ret) {
  138         gf_msg(this->name, GF_LOG_ERROR, 0, LEASE_MSG_INVAL_INODE_CTX,
  139                "inode_ctx_get failed");
  140         goto out;
  141     }
  142 
  143     inode_ctx = GF_CALLOC(1, sizeof(*inode_ctx),
  144                           gf_leases_mt_lease_inode_ctx_t);
  145     GF_CHECK_ALLOC(inode_ctx, ret, out);
  146 
  147     pthread_mutex_init(&inode_ctx->lock, NULL);
  148     INIT_LIST_HEAD(&inode_ctx->lease_id_list);
  149     INIT_LIST_HEAD(&inode_ctx->blocked_list);
  150 
  151     inode_ctx->lease_cnt = 0;
  152 
  153     ret = __inode_ctx_set(inode, this, (uint64_t *)inode_ctx);
  154     if (ret) {
  155         GF_FREE(inode_ctx);
  156         gf_msg(this->name, GF_LOG_INFO, 0, LEASE_MSG_INVAL_INODE_CTX,
  157                "failed to set inode ctx (%p)", inode);
  158     }
  159 out:
  160     return ret;
  161 }
  162 
  163 static lease_inode_ctx_t *
  164 __lease_ctx_get(inode_t *inode, xlator_t *this)
  165 {
  166     lease_inode_ctx_t *inode_ctx = NULL;
  167     uint64_t ctx = 0;
  168     int ret = 0;
  169 
  170     GF_VALIDATE_OR_GOTO("leases", inode, out);
  171     GF_VALIDATE_OR_GOTO("leases", this, out);
  172 
  173     ret = __inode_ctx_get(inode, this, &ctx);
  174     if (ret < 0) {
  175         ret = __lease_ctx_set(inode, this);
  176         if (ret < 0)
  177             goto out;
  178 
  179         ret = __inode_ctx_get(inode, this, &ctx);
  180         if (ret < 0) {
  181             gf_msg(this->name, GF_LOG_WARNING, 0, LEASE_MSG_INVAL_INODE_CTX,
  182                    "failed to get inode ctx (%p)", inode);
  183             goto out;
  184         }
  185     }
  186 
  187     inode_ctx = (lease_inode_ctx_t *)(long)ctx;
  188 out:
  189     return inode_ctx;
  190 }
  191 
  192 lease_inode_ctx_t *
  193 lease_ctx_get(inode_t *inode, xlator_t *this)
  194 {
  195     lease_inode_ctx_t *inode_ctx = NULL;
  196 
  197     GF_VALIDATE_OR_GOTO("leases", inode, out);
  198     GF_VALIDATE_OR_GOTO("leases", this, out);
  199 
  200     LOCK(&inode->lock);
  201     {
  202         inode_ctx = __lease_ctx_get(inode, this);
  203     }
  204     UNLOCK(&inode->lock);
  205 out:
  206     return inode_ctx;
  207 }
  208 
  209 static lease_id_entry_t *
  210 new_lease_id_entry(call_frame_t *frame, const char *lease_id)
  211 {
  212     lease_id_entry_t *lease_entry = NULL;
  213 
  214     GF_VALIDATE_OR_GOTO("leases", frame, out);
  215     GF_VALIDATE_OR_GOTO("leases", lease_id, out);
  216 
  217     lease_entry = GF_CALLOC(1, sizeof(*lease_entry),
  218                             gf_leases_mt_lease_id_entry_t);
  219     if (!lease_entry) {
  220         gf_msg(frame->this->name, GF_LOG_ERROR, ENOMEM, LEASE_MSG_NO_MEM,
  221                "Memory allocation for lease_entry failed");
  222         return NULL;
  223     }
  224 
  225     INIT_LIST_HEAD(&lease_entry->lease_id_list);
  226     lease_entry->lease_type = NONE;
  227     lease_entry->lease_cnt = 0;
  228     lease_entry->recall_time = get_recall_lease_timeout(frame->this);
  229     lease_entry->client_uid = gf_strdup(frame->root->client->client_uid);
  230     if (!lease_entry->client_uid) {
  231         gf_msg(frame->this->name, GF_LOG_ERROR, ENOMEM, LEASE_MSG_NO_MEM,
  232                "Memory allocation for client_uid failed");
  233         GF_FREE(lease_entry);
  234         lease_entry = NULL;
  235         goto out;
  236     }
  237 
  238     memcpy(lease_entry->lease_id, lease_id, LEASE_ID_SIZE);
  239 out:
  240     return lease_entry;
  241 }
  242 
  243 static void
  244 __destroy_lease_id_entry(lease_id_entry_t *lease_entry)
  245 {
  246     GF_VALIDATE_OR_GOTO("leases", lease_entry, out);
  247 
  248     list_del_init(&lease_entry->lease_id_list);
  249     GF_FREE(lease_entry->client_uid);
  250     GF_FREE(lease_entry);
  251 out:
  252     return;
  253 }
  254 
  255 static inline gf_boolean_t
  256 __is_same_lease_id(const char *k1, const char *k2)
  257 {
  258     if (memcmp(k1, k2, strlen(k1)) == 0)
  259         return _gf_true;
  260 
  261     return _gf_false;
  262 }
  263 
  264 /* Checks if there are any leases, other than the leases taken
  265  * by the given lease_id
  266  */
  267 static gf_boolean_t
  268 __another_lease_found(lease_inode_ctx_t *lease_ctx, const char *lease_id)
  269 {
  270     lease_id_entry_t *lease_entry = NULL;
  271     lease_id_entry_t *tmp = NULL;
  272     gf_boolean_t found_lease = _gf_false;
  273 
  274     GF_VALIDATE_OR_GOTO("leases", lease_id, out);
  275     GF_VALIDATE_OR_GOTO("leases", lease_ctx, out);
  276 
  277     list_for_each_entry_safe(lease_entry, tmp, &lease_ctx->lease_id_list,
  278                              lease_id_list)
  279     {
  280         if (!__is_same_lease_id(lease_id, lease_entry->lease_id)) {
  281             if (lease_entry->lease_cnt > 0) {
  282                 found_lease = _gf_true;
  283                 break;
  284             }
  285         }
  286     }
  287 out:
  288     return found_lease;
  289 }
  290 
  291 /* Returns the lease_id_entry for a given lease_id and a given inode.
  292  * Return values:
  293  * NULL - If no client entry found
  294  * lease_id_entry_t* - a pointer to the client entry if found
  295  */
  296 static lease_id_entry_t *
  297 __get_lease_id_entry(lease_inode_ctx_t *lease_ctx, const char *lease_id)
  298 {
  299     lease_id_entry_t *lease_entry = NULL;
  300     lease_id_entry_t *tmp = NULL;
  301     lease_id_entry_t *found = NULL;
  302 
  303     GF_VALIDATE_OR_GOTO("leases", lease_id, out);
  304     GF_VALIDATE_OR_GOTO("leases", lease_ctx, out);
  305 
  306     list_for_each_entry_safe(lease_entry, tmp, &lease_ctx->lease_id_list,
  307                              lease_id_list)
  308     {
  309         if (__is_same_lease_id(lease_id, lease_entry->lease_id)) {
  310             found = lease_entry;
  311             gf_msg_debug("leases", 0,
  312                          "lease ID entry found "
  313                          "Client UID:%s, lease id:%s",
  314                          lease_entry->client_uid,
  315                          leaseid_utoa(lease_entry->lease_id));
  316             break;
  317         }
  318     }
  319 out:
  320     return found;
  321 }
  322 
  323 /* Returns the lease_id_entry for a given lease_id and a given inode,
  324  * if none found creates one.
  325  * Return values:
  326  * lease_id_entry_t* - a pointer to the client entry
  327  */
  328 static lease_id_entry_t *
  329 __get_or_new_lease_entry(call_frame_t *frame, const char *lease_id,
  330                          lease_inode_ctx_t *lease_ctx)
  331 {
  332     lease_id_entry_t *lease_entry = NULL;
  333 
  334     GF_VALIDATE_OR_GOTO("leases", frame, out);
  335     GF_VALIDATE_OR_GOTO("leases", lease_id, out);
  336     GF_VALIDATE_OR_GOTO("leases", lease_ctx, out);
  337 
  338     lease_entry = __get_lease_id_entry(lease_ctx, lease_id);
  339     if (!lease_entry) { /* create one */
  340         lease_entry = new_lease_id_entry(frame, lease_id);
  341         if (!lease_entry)
  342             goto out;
  343 
  344         list_add_tail(&lease_entry->lease_id_list, &lease_ctx->lease_id_list);
  345 
  346         gf_msg_debug(frame->this->name, 0,
  347                      "lease ID entry added,"
  348                      " Client UID:%s, lease id:%s",
  349                      lease_entry->client_uid,
  350                      leaseid_utoa(lease_entry->lease_id));
  351     }
  352 out:
  353     return lease_entry;
  354 }
  355 
  356 static lease_inode_t *
  357 new_lease_inode(inode_t *inode)
  358 {
  359     lease_inode_t *l_inode = GF_MALLOC(sizeof(*l_inode),
  360                                        gf_leases_mt_lease_inode_t);
  361     if (!l_inode)
  362         goto out;
  363 
  364     INIT_LIST_HEAD(&l_inode->list);
  365     l_inode->inode = inode_ref(inode);
  366 out:
  367     return l_inode;
  368 }
  369 
  370 static void
  371 __destroy_lease_inode(lease_inode_t *l_inode)
  372 {
  373     list_del_init(&l_inode->list);
  374     inode_unref(l_inode->inode);
  375     GF_FREE(l_inode);
  376 }
  377 
  378 static lease_client_t *
  379 new_lease_client(const char *client_uid)
  380 {
  381     lease_client_t *clnt = GF_MALLOC(sizeof(*clnt),
  382                                      gf_leases_mt_lease_client_t);
  383     if (!clnt)
  384         goto out;
  385 
  386     INIT_LIST_HEAD(&clnt->client_list);
  387     INIT_LIST_HEAD(&clnt->inode_list);
  388     clnt->client_uid = gf_strdup(client_uid);
  389 out:
  390     return clnt;
  391 }
  392 
  393 static void
  394 __destroy_lease_client(lease_client_t *clnt)
  395 {
  396     list_del_init(&clnt->inode_list);
  397     list_del_init(&clnt->client_list);
  398     GF_FREE(clnt);
  399 
  400     return;
  401 }
  402 
  403 static lease_client_t *
  404 __get_lease_client(xlator_t *this, leases_private_t *priv,
  405                    const char *client_uid)
  406 {
  407     lease_client_t *clnt = NULL;
  408     lease_client_t *tmp = NULL;
  409     lease_client_t *found = NULL;
  410 
  411     list_for_each_entry_safe(clnt, tmp, &priv->client_list, client_list)
  412     {
  413         if ((strcmp(clnt->client_uid, client_uid) == 0)) {
  414             found = clnt;
  415             gf_msg_debug(this->name, 0,
  416                          "Client:%s already found "
  417                          "in the cleanup list",
  418                          client_uid);
  419             break;
  420         }
  421     }
  422     return found;
  423 }
  424 
  425 static lease_client_t *
  426 __get_or_new_lease_client(xlator_t *this, leases_private_t *priv,
  427                           const char *client_uid)
  428 {
  429     lease_client_t *found = NULL;
  430 
  431     found = __get_lease_client(this, priv, client_uid);
  432     if (!found) {
  433         found = new_lease_client(client_uid);
  434         if (!found)
  435             goto out;
  436         list_add_tail(&found->client_list, &priv->client_list);
  437         gf_msg_debug(this->name, 0,
  438                      "Adding a new client:%s entry "
  439                      "to the cleanup list",
  440                      client_uid);
  441     }
  442 out:
  443     return found;
  444 }
  445 
  446 static int
  447 add_inode_to_client_list(xlator_t *this, inode_t *inode, const char *client_uid)
  448 {
  449     leases_private_t *priv = this->private;
  450     lease_client_t *clnt = NULL;
  451 
  452     lease_inode_t *lease_inode = new_lease_inode(inode);
  453     if (!lease_inode)
  454         return -ENOMEM;
  455 
  456     pthread_mutex_lock(&priv->mutex);
  457     {
  458         clnt = __get_or_new_lease_client(this, priv, client_uid);
  459         if (!clnt) {
  460             pthread_mutex_unlock(&priv->mutex);
  461             __destroy_lease_inode(lease_inode);
  462             return -ENOMEM;
  463         }
  464         list_add_tail(&clnt->inode_list, &lease_inode->list);
  465     }
  466     pthread_mutex_unlock(&priv->mutex);
  467     gf_msg_debug(this->name, 0,
  468                  "Added a new inode:%p to the client(%s) "
  469                  "cleanup list, gfid(%s)",
  470                  inode, client_uid, uuid_utoa(inode->gfid));
  471     return 0;
  472 }
  473 
  474 /* Add lease entry to the corresponding client entry.
  475  * Return values:
  476  * 0 Success
  477  * -1 Failure
  478  */
  479 static int
  480 __add_lease(call_frame_t *frame, inode_t *inode, lease_inode_ctx_t *lease_ctx,
  481             const char *client_uid, struct gf_lease *lease)
  482 {
  483     lease_id_entry_t *lease_entry = NULL;
  484     int ret = -1;
  485 
  486     GF_VALIDATE_OR_GOTO("leases", frame, out);
  487     GF_VALIDATE_OR_GOTO("leases", client_uid, out);
  488     GF_VALIDATE_OR_GOTO("leases", lease_ctx, out);
  489     GF_VALIDATE_OR_GOTO("leases", inode, out);
  490     GF_VALIDATE_OR_GOTO("leases", lease, out);
  491 
  492     gf_msg_trace(frame->this->name, 0,
  493                  "Granting lease lock to client %s with lease id %s"
  494                  " on gfid(%s)",
  495                  client_uid, leaseid_utoa(lease->lease_id),
  496                  uuid_utoa(inode->gfid));
  497 
  498     lease_entry = __get_or_new_lease_entry(frame, lease->lease_id, lease_ctx);
  499     if (!lease_entry) {
  500         errno = ENOMEM;
  501         goto out;
  502     }
  503 
  504     lease_entry->lease_type_cnt[lease->lease_type]++;
  505     lease_entry->lease_cnt++;
  506     lease_entry->lease_type |= lease->lease_type;
  507     /* If this is the first lease taken by the client on the file, then
  508      * add this inode/file to the client disconnect cleanup list
  509      */
  510     if (lease_entry->lease_cnt == 1) {
  511         add_inode_to_client_list(frame->this, inode, client_uid);
  512     }
  513 
  514     lease_ctx->lease_cnt++;
  515     lease_ctx->lease_type_cnt[lease->lease_type]++;
  516     lease_ctx->lease_type |= lease->lease_type;
  517 
  518     /* Take a ref for the first lock taken on this inode. Corresponding
  519      * unref when all the leases are unlocked or during DISCONNECT
  520      * Ref is required because the inode on which lease is acquired should
  521      * not be deleted when lru cleanup kicks in*/
  522     if (lease_ctx->lease_cnt == 1) {
  523         lease_ctx->inode = inode_ref(inode);
  524     }
  525 
  526     ret = 0;
  527 out:
  528     return ret;
  529 }
  530 
  531 static gf_boolean_t
  532 __is_clnt_lease_none(const char *client_uid, lease_inode_ctx_t *lease_ctx)
  533 {
  534     gf_boolean_t lease_none = _gf_true;
  535     lease_id_entry_t *lease_entry = NULL;
  536     lease_id_entry_t *tmp = NULL;
  537 
  538     list_for_each_entry_safe(lease_entry, tmp, &lease_ctx->lease_id_list,
  539                              lease_id_list)
  540     {
  541         if ((strcmp(client_uid, lease_entry->client_uid) == 0) &&
  542             (lease_entry->lease_cnt != 0)) {
  543             lease_none = _gf_false;
  544             break;
  545         }
  546     }
  547 
  548     return lease_none;
  549 }
  550 
  551 static int
  552 __remove_inode_from_clnt_list(xlator_t *this, lease_client_t *clnt,
  553                               inode_t *inode)
  554 {
  555     int ret = -1;
  556     lease_inode_t *l_inode = NULL;
  557     lease_inode_t *tmp1 = NULL;
  558 
  559     list_for_each_entry_safe(l_inode, tmp1, &clnt->inode_list, list)
  560     {
  561         if (l_inode->inode == inode) {
  562             __destroy_lease_inode(l_inode);
  563             gf_msg_debug(this->name, 0,
  564                          "Removed the inode from the client cleanup list");
  565             ret = 0;
  566         }
  567     }
  568     /* TODO: Remove the client entry from the cleanup list */
  569 
  570     return ret;
  571 }
  572 
  573 static int
  574 remove_from_clnt_list(xlator_t *this, const char *client_uid, inode_t *inode)
  575 {
  576     leases_private_t *priv = NULL;
  577     int ret = -1;
  578     lease_client_t *clnt = NULL;
  579 
  580     priv = this->private;
  581     if (!priv)
  582         goto out;
  583 
  584     pthread_mutex_lock(&priv->mutex);
  585     {
  586         clnt = __get_lease_client(this, priv, client_uid);
  587         if (!clnt) {
  588             pthread_mutex_unlock(&priv->mutex);
  589             gf_msg(this->name, GF_LOG_ERROR, 0, LEASE_MSG_CLNT_NOTFOUND,
  590                    "There is no client entry found in the cleanup list");
  591             goto out;
  592         }
  593         ret = __remove_inode_from_clnt_list(this, clnt, inode);
  594         if (ret) {
  595             pthread_mutex_unlock(&priv->mutex);
  596             gf_msg(this->name, GF_LOG_ERROR, 0, LEASE_MSG_INODE_NOTFOUND,
  597                    "There is no inode entry found in the cleanup list");
  598             goto out;
  599         }
  600     }
  601     pthread_mutex_unlock(&priv->mutex);
  602 out:
  603     return ret;
  604 }
  605 
  606 /* Remove lease entry in the corresponding client entry.
  607  */
  608 static int
  609 __remove_lease(xlator_t *this, inode_t *inode, lease_inode_ctx_t *lease_ctx,
  610                const char *client_uid, struct gf_lease *lease)
  611 {
  612     lease_id_entry_t *lease_entry = NULL;
  613     int ret = 0;
  614     int32_t lease_type = 0;
  615     leases_private_t *priv = NULL;
  616 
  617     GF_VALIDATE_OR_GOTO("leases", lease_ctx, out);
  618     GF_VALIDATE_OR_GOTO("leases", lease, out);
  619 
  620     priv = this->private;
  621 
  622     gf_msg_trace(this->name, 0,
  623                  "Removing lease entry for client: %s, "
  624                  "lease type:%d, lease id:%s",
  625                  client_uid, lease->lease_type, leaseid_utoa(lease->lease_id));
  626 
  627     /* There could be a race where in server recalled the lease and by the time
  628      * client sends lease_unlock request, server may have revoked it. To handle
  629      * such cases, if lease doesnt exist treat it as noop and return success.
  630      */
  631     lease_entry = __get_lease_id_entry(lease_ctx, lease->lease_id);
  632     if (!lease_entry) {
  633         gf_msg(this->name, GF_LOG_INFO, 0, LEASE_MSG_INVAL_UNLK_LEASE,
  634                "Got unlock lease request from client:%s, but has no "
  635                "corresponding lock",
  636                client_uid);
  637         ret = 0;
  638         goto out;
  639     }
  640 
  641     if (!(lease_entry->lease_type & lease->lease_type)) {
  642         gf_msg(this->name, GF_LOG_INFO, 0, LEASE_MSG_INVAL_UNLK_LEASE,
  643                "Got unlock lease request from client:%s for an invalid "
  644                "lease_type",
  645                client_uid);
  646         ret = -EINVAL;
  647         errno = EINVAL;
  648         goto out;
  649     }
  650     lease_type = lease->lease_type;
  651     lease_entry->lease_type_cnt[lease_type]--;
  652     lease_entry->lease_cnt--;
  653 
  654     lease_ctx->lease_type_cnt[lease_type]--;
  655     lease_ctx->lease_cnt--;
  656 
  657     if (lease_entry->lease_type_cnt[lease_type] == 0)
  658         lease_entry->lease_type = lease_entry->lease_type & (~lease_type);
  659 
  660     if (lease_ctx->lease_type_cnt[lease_type] == 0)
  661         lease_ctx->lease_type = lease_ctx->lease_type & (~lease_type);
  662 
  663     if (lease_entry->lease_cnt == 0) {
  664         if (__is_clnt_lease_none(client_uid, lease_ctx)) {
  665             gf_msg_trace(this->name, 0,
  666                          "Client(%s) has no leases"
  667                          " on gfid (%s), hence removing the inode"
  668                          " from the client cleanup list",
  669                          client_uid, uuid_utoa(inode->gfid));
  670             remove_from_clnt_list(this, client_uid, lease_ctx->inode);
  671         }
  672         __destroy_lease_id_entry(lease_entry);
  673         lease_ctx->blocked_fops_resuming = _gf_true;
  674     }
  675 
  676     if (lease_ctx->lease_cnt == 0 && lease_ctx->timer) {
  677         ret = gf_tw_del_timer(priv->timer_wheel, lease_ctx->timer);
  678         lease_ctx->recall_in_progress = _gf_false;
  679         lease_ctx->timer = NULL;
  680     }
  681 out:
  682     return ret;
  683 }
  684 
  685 static gf_boolean_t
  686 __is_lease_grantable(xlator_t *this, lease_inode_ctx_t *lease_ctx,
  687                      struct gf_lease *lease, inode_t *inode)
  688 {
  689     uint32_t fd_count = 0;
  690     int32_t flags = 0;
  691     fd_t *iter_fd = NULL;
  692     gf_boolean_t grant = _gf_false;
  693     int ret = 0;
  694     lease_fd_ctx_t *fd_ctx = NULL;
  695     uint64_t ctx = 0;
  696 
  697     GF_VALIDATE_OR_GOTO("leases", lease_ctx, out);
  698     GF_VALIDATE_OR_GOTO("leases", lease, out);
  699     GF_VALIDATE_OR_GOTO("leases", inode, out);
  700 
  701     if (lease_ctx->recall_in_progress) {
  702         gf_msg_debug(this->name, 0,
  703                      "Recall in progress, hence "
  704                      "failing the lease request");
  705         grant = _gf_false;
  706         goto out;
  707     }
  708 
  709     if (lease_ctx->blocked_fops_resuming) {
  710         gf_msg_debug(this->name, 0,
  711                      "Previously blocked fops resuming, hence "
  712                      "failing the lease request");
  713         grant = _gf_false;
  714         goto out;
  715     }
  716 
  717     LOCK(&inode->lock);
  718     {
  719         list_for_each_entry(iter_fd, &inode->fd_list, inode_list)
  720         {
  721             ret = fd_ctx_get(iter_fd, this, &ctx);
  722             if (ret < 0) {
  723                 grant = _gf_false;
  724                 UNLOCK(&inode->lock);
  725                 gf_msg(this->name, GF_LOG_ERROR, 0, LEASE_MSG_INVAL_FD_CTX,
  726                        "Unable to get fd ctx");
  727                 goto out;
  728             }
  729             fd_ctx = (lease_fd_ctx_t *)(long)ctx;
  730 
  731             /* Check for open fd conflict, note that open fds from
  732              * the same lease id is not checked for conflict, as it is
  733              * lease id based lease.
  734              */
  735             if (fd_ctx->client_uid != NULL &&
  736                 !__is_same_lease_id(fd_ctx->lease_id, lease->lease_id)) {
  737                 fd_count++;
  738                 flags |= iter_fd->flags;
  739             }
  740         }
  741     }
  742     UNLOCK(&inode->lock);
  743 
  744     gf_msg_debug(this->name, 0, "open fd count:%d flags:%d", fd_count, flags);
  745 
  746     __dump_leases_info(this, lease_ctx);
  747 
  748     switch (lease->lease_type) {
  749         case GF_RD_LEASE:
  750             /* check open fd conflict */
  751             if ((fd_count > 0) && ((flags & O_WRONLY) || (flags & O_RDWR))) {
  752                 grant = _gf_false;
  753                 break;
  754             }
  755 
  756             /* check for conflict with existing leases */
  757             if (lease_ctx->lease_type == NONE ||
  758                 lease_ctx->lease_type == GF_RD_LEASE ||
  759                 !(__another_lease_found(lease_ctx, lease->lease_id)))
  760                 grant = _gf_true;
  761             else
  762                 grant = _gf_false;
  763             break;
  764 
  765         case GF_RW_LEASE:
  766             /* check open fd conflict; conflict if there are any fds open
  767              * other than the client on which the lease is requested. */
  768             if (fd_count > 0) {
  769                 grant = _gf_false;
  770                 break;
  771             }
  772 
  773             /* check existing lease conflict */
  774             if (lease_ctx->lease_type == NONE ||
  775                 !(__another_lease_found(lease_ctx, lease->lease_id)))
  776                 grant = _gf_true;
  777             else
  778                 grant = _gf_false;
  779             break;
  780 
  781         default:
  782             gf_msg(this->name, GF_LOG_ERROR, EINVAL, LEASE_MSG_INVAL_LEASE_TYPE,
  783                    "Invalid lease type specified");
  784             break;
  785     }
  786 out:
  787     return grant;
  788 }
  789 
  790 static void
  791 do_blocked_fops(xlator_t *this, lease_inode_ctx_t *lease_ctx)
  792 {
  793     struct list_head wind_list;
  794     fop_stub_t *blk_fop = NULL;
  795     fop_stub_t *tmp = NULL;
  796 
  797     INIT_LIST_HEAD(&wind_list);
  798 
  799     pthread_mutex_lock(&lease_ctx->lock);
  800     {
  801         if (!lease_ctx->blocked_fops_resuming) {
  802             /* lease_ctx->blocked_fops_resuming will be set
  803              * only when the last lease is released. That
  804              * is when we need to resume blocked fops and unref
  805              * the inode taken in __add_lease (when lease_cnt == 1).
  806              * Return otherwise.
  807              */
  808             pthread_mutex_unlock(&lease_ctx->lock);
  809             return;
  810         }
  811 
  812         list_for_each_entry_safe(blk_fop, tmp, &lease_ctx->blocked_list, list)
  813         {
  814             list_del_init(&blk_fop->list);
  815             list_add_tail(&blk_fop->list, &wind_list);
  816         }
  817     }
  818     pthread_mutex_unlock(&lease_ctx->lock);
  819 
  820     gf_msg_trace(this->name, 0, "Executing the blocked stubs on gfid(%s)",
  821                  uuid_utoa(lease_ctx->inode->gfid));
  822     list_for_each_entry_safe(blk_fop, tmp, &wind_list, list)
  823     {
  824         list_del_init(&blk_fop->list);
  825         gf_msg_trace(this->name, 0, "Executing fop:%d", blk_fop->stub->fop);
  826         call_resume(blk_fop->stub);
  827         GF_FREE(blk_fop);
  828     }
  829 
  830     pthread_mutex_lock(&lease_ctx->lock);
  831     {
  832         lease_ctx->lease_type = NONE;
  833         /* unref the inode taken in __add_lease
  834          * (when lease_cnt == 1) */
  835         lease_ctx->blocked_fops_resuming = _gf_false;
  836         inode_unref(lease_ctx->inode);
  837         lease_ctx->inode = NULL;
  838     }
  839     pthread_mutex_unlock(&lease_ctx->lock);
  840 
  841     return;
  842 }
  843 
  844 void
  845 recall_lease_timer_handler(struct gf_tw_timer_list *timer, void *data,
  846                            unsigned long calltime)
  847 {
  848     inode_t *inode = NULL;
  849     lease_inode_t *lease_inode = NULL;
  850     leases_private_t *priv = NULL;
  851     lease_timer_data_t *timer_data = NULL;
  852 
  853     timer_data = data;
  854 
  855     priv = timer_data->this->private;
  856     inode = timer_data->inode;
  857     lease_inode = new_lease_inode(inode);
  858     if (!lease_inode) {
  859         errno = ENOMEM;
  860         goto out;
  861     }
  862     pthread_mutex_lock(&priv->mutex);
  863     {
  864         list_add_tail(&lease_inode->list, &priv->recall_list);
  865         pthread_cond_broadcast(&priv->cond);
  866     }
  867     pthread_mutex_unlock(&priv->mutex);
  868 out:
  869     /* unref the inode_ref taken by timer_data in __recall_lease */
  870     inode_unref(timer_data->inode);
  871 
  872     GF_FREE(timer);
  873 }
  874 
  875 static void
  876 __recall_lease(xlator_t *this, lease_inode_ctx_t *lease_ctx)
  877 {
  878     lease_id_entry_t *lease_entry = NULL;
  879     lease_id_entry_t *tmp = NULL;
  880     struct gf_upcall up_req = {
  881         0,
  882     };
  883     struct gf_upcall_recall_lease recall_req = {
  884         0,
  885     };
  886     int notify_ret = -1;
  887     struct gf_tw_timer_list *timer = NULL;
  888     leases_private_t *priv = NULL;
  889     lease_timer_data_t *timer_data = NULL;
  890     time_t recall_time;
  891 
  892     if (lease_ctx->recall_in_progress) {
  893         gf_msg_debug(this->name, 0,
  894                      "Lease recall is already in "
  895                      "progress, hence not sending another recall");
  896         goto out;
  897     }
  898 
  899     priv = this->private;
  900     recall_time = time(NULL);
  901     list_for_each_entry_safe(lease_entry, tmp, &lease_ctx->lease_id_list,
  902                              lease_id_list)
  903     {
  904         gf_uuid_copy(up_req.gfid, lease_ctx->inode->gfid);
  905         up_req.client_uid = lease_entry->client_uid;
  906         up_req.event_type = GF_UPCALL_RECALL_LEASE;
  907         up_req.data = &recall_req;
  908 
  909         notify_ret = this->notify(this, GF_EVENT_UPCALL, &up_req);
  910         if (notify_ret < 0) {
  911             gf_msg(this->name, GF_LOG_ERROR, 0, LEASE_MSG_RECALL_FAIL,
  912                    "Recall notification to client: %s failed",
  913                    lease_entry->client_uid);
  914             /* Do not return from here, continue registering the timer,
  915                this is required mostly o keep replicas in sync*/
  916         } else {
  917             gf_msg_debug(this->name, 0,
  918                          "Recall lease (all)"
  919                          "notification sent to client %s",
  920                          lease_entry->client_uid);
  921         }
  922 
  923         lease_ctx->recall_in_progress = _gf_true;
  924         lease_entry->recall_time = recall_time;
  925     }
  926     timer = GF_MALLOC(sizeof(*timer), gf_common_mt_tw_timer_list);
  927     if (!timer) {
  928         goto out;
  929     }
  930     timer_data = GF_MALLOC(sizeof(lease_timer_data_t),
  931                            gf_leases_mt_timer_data_t);
  932     if (!timer_data) {
  933         GF_FREE(timer);
  934         goto out;
  935     }
  936 
  937     timer_data->inode = inode_ref(lease_ctx->inode);
  938     timer_data->this = this;
  939     timer->data = timer_data;
  940 
  941     INIT_LIST_HEAD(&timer->entry);
  942     timer->expires = get_recall_lease_timeout(this);
  943     timer->function = recall_lease_timer_handler;
  944     lease_ctx->timer = timer;
  945     gf_tw_add_timer(priv->timer_wheel, timer);
  946     gf_msg_trace(this->name, 0,
  947                  "Registering timer "
  948                  "%p, after "
  949                  "sending recall",
  950                  timer);
  951 out:
  952     return;
  953 }
  954 
  955 /* ret = 0; STACK_UNWIND Success
  956  * ret = -1; STACK_UNWIND failure
  957  */
  958 int
  959 process_lease_req(call_frame_t *frame, xlator_t *this, inode_t *inode,
  960                   struct gf_lease *lease)
  961 {
  962     int ret = 0;
  963     char *client_uid = NULL;
  964     lease_inode_ctx_t *lease_ctx = NULL;
  965 
  966     GF_VALIDATE_OR_GOTO("leases", frame, out);
  967     GF_VALIDATE_OR_GOTO("leases", this, out);
  968     GF_VALIDATE_OR_GOTO("leases", inode, out);
  969     GF_VALIDATE_OR_GOTO("leases", lease, out);
  970 
  971     client_uid = frame->root->client->client_uid;
  972 
  973     if (!is_valid_lease_id(lease->lease_id)) {
  974         gf_msg(this->name, GF_LOG_ERROR, EINVAL, LEASE_MSG_INVAL_LEASE_ID,
  975                "Invalid lease id, from"
  976                "client:%s",
  977                client_uid);
  978         ret = -EINVAL;
  979         errno = EINVAL;
  980         goto out;
  981     }
  982 
  983     lease_ctx = lease_ctx_get(inode, this);
  984     if (!lease_ctx) {
  985         gf_msg(this->name, GF_LOG_WARNING, ENOMEM, LEASE_MSG_NO_MEM,
  986                "Unable to create/get inode ctx, "
  987                "inode:%p",
  988                inode);
  989         ret = -ENOMEM;
  990         errno = ENOMEM;
  991         goto out;
  992     }
  993 
  994     gf_msg_debug(this->name, 0,
  995                  "Lease request from client: %s, "
  996                  "lease type:%d, lease cmd:%d, lease ID:%s, gfid:%s",
  997                  client_uid, lease->lease_type, lease->cmd,
  998                  leaseid_utoa(lease->lease_id), uuid_utoa(inode->gfid));
  999 
 1000     pthread_mutex_lock(&lease_ctx->lock);
 1001     {
 1002         switch (lease->cmd) {
 1003             case GF_GET_LEASE:
 1004                 lease->lease_type = lease_ctx->lease_type;
 1005                 gf_msg_debug(this->name, 0,
 1006                              "Get lease, existing lease"
 1007                              "type: %d",
 1008                              lease_ctx->lease_type);
 1009                 /*TODO:Should it consider lease id or client_uid?*/
 1010                 break;
 1011 
 1012             case GF_SET_LEASE:
 1013                 if (__is_lease_grantable(this, lease_ctx, lease, inode)) {
 1014                     __add_lease(frame, inode, lease_ctx, client_uid, lease);
 1015                     ret = 0;
 1016                 } else {
 1017                     gf_msg_debug(this->name, GF_LOG_DEBUG,
 1018                                  "Not granting the conflicting lease"
 1019                                  " request from %s on gfid(%s)",
 1020                                  client_uid, uuid_utoa(inode->gfid));
 1021                     __recall_lease(this, lease_ctx);
 1022                     ret = -1;
 1023                 }
 1024                 break;
 1025             case GF_UNLK_LEASE:
 1026                 ret = __remove_lease(this, inode, lease_ctx, client_uid, lease);
 1027                 if ((ret >= 0) && (lease_ctx->lease_cnt == 0)) {
 1028                     pthread_mutex_unlock(&lease_ctx->lock);
 1029                     goto unblock;
 1030                 }
 1031                 break;
 1032             default:
 1033                 ret = -EINVAL;
 1034                 break;
 1035         }
 1036     }
 1037     pthread_mutex_unlock(&lease_ctx->lock);
 1038 
 1039     return ret;
 1040 
 1041 unblock:
 1042     do_blocked_fops(this, lease_ctx);
 1043 out:
 1044     return ret;
 1045 }
 1046 
 1047 /* ret = 1 conflict
 1048  * ret = 0 no conflict
 1049  */
 1050 gf_boolean_t
 1051 __check_lease_conflict(call_frame_t *frame, lease_inode_ctx_t *lease_ctx,
 1052                        const char *lease_id, gf_boolean_t is_write)
 1053 {
 1054     gf_lease_types_t lease_type = {
 1055         0,
 1056     };
 1057     gf_boolean_t conflicts = _gf_false;
 1058     lease_id_entry_t *lease_entry = NULL;
 1059 
 1060     GF_VALIDATE_OR_GOTO("leases", frame, out);
 1061     GF_VALIDATE_OR_GOTO("leases", lease_ctx, out);
 1062 
 1063     lease_type = lease_ctx->lease_type;
 1064 
 1065     /* If the fop is rename or unlink conflict the lease even if its
 1066      * from the same client??
 1067      */
 1068     if ((frame->root->op == GF_FOP_RENAME) ||
 1069         (frame->root->op == GF_FOP_UNLINK)) {
 1070         conflicts = _gf_true;
 1071         goto recall;
 1072     }
 1073 
 1074     /* As internal fops are used to maintain data integrity but do not
 1075      * make modififications to the client data, no need to conflict with
 1076      * them.
 1077      *
 1078      * @todo: like for locks, even lease state has to be handled by
 1079      * rebalance or self-heal daemon process. */
 1080     if (frame->root->pid < 0) {
 1081         conflicts = _gf_false;
 1082         goto recall;
 1083     }
 1084 
 1085     /* If lease_id is not sent, set conflicts = true if there is
 1086      * an existing lease */
 1087     if (!lease_id && (lease_ctx->lease_cnt > 0)) {
 1088         conflicts = _gf_true;
 1089         goto recall;
 1090     }
 1091 
 1092     switch (lease_type) {
 1093         case (GF_RW_LEASE | GF_RD_LEASE):
 1094         case GF_RW_LEASE:
 1095             lease_entry = __get_lease_id_entry(lease_ctx, lease_id);
 1096             if (lease_entry && (lease_entry->lease_type & GF_RW_LEASE))
 1097                 conflicts = _gf_false;
 1098             else
 1099                 conflicts = _gf_true;
 1100             break;
 1101         case GF_RD_LEASE:
 1102             if (is_write && __another_lease_found(lease_ctx, lease_id))
 1103                 conflicts = _gf_true;
 1104             else
 1105                 conflicts = _gf_false;
 1106             break;
 1107         default:
 1108             break;
 1109     }
 1110 
 1111 recall:
 1112     /* If there is a conflict found and recall is not already sent to all
 1113      * the clients, then send recall to each of the client holding lease.
 1114      */
 1115     if (conflicts)
 1116         __recall_lease(frame->this, lease_ctx);
 1117 out:
 1118     return conflicts;
 1119 }
 1120 
 1121 /* Return values:
 1122  * -1 : error, unwind the fop
 1123  * WIND_FOP: No conflict, wind the fop
 1124  * BLOCK_FOP: Found a conflicting lease, block the fop
 1125  */
 1126 int
 1127 check_lease_conflict(call_frame_t *frame, inode_t *inode, const char *lease_id,
 1128                      uint32_t fop_flags)
 1129 {
 1130     lease_inode_ctx_t *lease_ctx = NULL;
 1131     gf_boolean_t is_blocking_fop = _gf_false;
 1132     gf_boolean_t is_write_fop = _gf_false;
 1133     gf_boolean_t conflicts = _gf_false;
 1134     int ret = WIND_FOP;
 1135 
 1136     lease_ctx = lease_ctx_get(inode, frame->this);
 1137     if (!lease_ctx) {
 1138         gf_msg(frame->this->name, GF_LOG_WARNING, ENOMEM, LEASE_MSG_NO_MEM,
 1139                "Unable to create/get inode ctx");
 1140         ret = -1;
 1141         errno = ENOMEM;
 1142         goto out;
 1143     }
 1144 
 1145     is_blocking_fop = ((fop_flags & BLOCKING_FOP) != 0);
 1146     is_write_fop = ((fop_flags & DATA_MODIFY_FOP) != 0);
 1147 
 1148     pthread_mutex_lock(&lease_ctx->lock);
 1149     {
 1150         if (lease_ctx->lease_type == NONE) {
 1151             pthread_mutex_unlock(&lease_ctx->lock);
 1152             gf_msg_debug(frame->this->name, 0,
 1153                          "No leases found continuing with the"
 1154                          " fop:%s",
 1155                          gf_fop_list[frame->root->op]);
 1156             ret = WIND_FOP;
 1157             goto out;
 1158         }
 1159         conflicts = __check_lease_conflict(frame, lease_ctx, lease_id,
 1160                                            is_write_fop);
 1161         if (conflicts) {
 1162             if (is_blocking_fop) {
 1163                 gf_msg_debug(frame->this->name, 0,
 1164                              "Fop: %s "
 1165                              "conflicting existing "
 1166                              "lease: %d, blocking the"
 1167                              "fop",
 1168                              gf_fop_list[frame->root->op],
 1169                              lease_ctx->lease_type);
 1170                 ret = BLOCK_FOP;
 1171             } else {
 1172                 gf_msg_debug(frame->this->name, 0,
 1173                              "Fop: %s "
 1174                              "conflicting existing "
 1175                              "lease: %d, sending "
 1176                              "EAGAIN",
 1177                              gf_fop_list[frame->root->op],
 1178                              lease_ctx->lease_type);
 1179                 errno = EAGAIN;
 1180                 ret = -1;
 1181             }
 1182         }
 1183     }
 1184     pthread_mutex_unlock(&lease_ctx->lock);
 1185 out:
 1186     return ret;
 1187 }
 1188 
 1189 static int
 1190 remove_clnt_leases(const char *client_uid, inode_t *inode, xlator_t *this)
 1191 {
 1192     lease_inode_ctx_t *lease_ctx = NULL;
 1193     lease_id_entry_t *lease_entry = NULL;
 1194     lease_id_entry_t *tmp = NULL;
 1195     int ret = 0;
 1196     int i = 0;
 1197 
 1198     lease_ctx = lease_ctx_get(inode, this);
 1199     if (!lease_ctx) {
 1200         gf_msg(this->name, GF_LOG_WARNING, ENOMEM, LEASE_MSG_INVAL_INODE_CTX,
 1201                "Unable to create/get inode ctx");
 1202         ret = -1;
 1203         errno = ENOMEM;
 1204         goto out;
 1205     }
 1206 
 1207     pthread_mutex_lock(&lease_ctx->lock);
 1208     {
 1209         list_for_each_entry_safe(lease_entry, tmp, &lease_ctx->lease_id_list,
 1210                                  lease_id_list)
 1211         {
 1212             if (strcmp(client_uid, lease_entry->client_uid) == 0) {
 1213                 for (i = 0; i < GF_LEASE_MAX_TYPE; i++) {
 1214                     lease_ctx->lease_type_cnt[i] -= lease_entry
 1215                                                         ->lease_type_cnt[i];
 1216                 }
 1217                 lease_ctx->lease_cnt -= lease_entry->lease_cnt;
 1218                 __destroy_lease_id_entry(lease_entry);
 1219                 if (lease_ctx->lease_cnt == 0) {
 1220                     lease_ctx->blocked_fops_resuming = _gf_true;
 1221                     pthread_mutex_unlock(&lease_ctx->lock);
 1222                     goto unblock;
 1223                 }
 1224             }
 1225         }
 1226     }
 1227     pthread_mutex_unlock(&lease_ctx->lock);
 1228 out:
 1229     return ret;
 1230 
 1231 unblock:
 1232     do_blocked_fops(this, lease_ctx);
 1233     return ret;
 1234 }
 1235 
 1236 int
 1237 cleanup_client_leases(xlator_t *this, const char *client_uid)
 1238 {
 1239     lease_client_t *clnt = NULL;
 1240     lease_client_t *tmp = NULL;
 1241     struct list_head cleanup_list = {
 1242         0,
 1243     };
 1244     lease_inode_t *l_inode = NULL;
 1245     lease_inode_t *tmp1 = NULL;
 1246     leases_private_t *priv = NULL;
 1247     int ret = 0;
 1248 
 1249     priv = this->private;
 1250     if (!priv) {
 1251         ret = -1;
 1252         errno = EINVAL;
 1253         goto out;
 1254     }
 1255 
 1256     INIT_LIST_HEAD(&cleanup_list);
 1257     pthread_mutex_lock(&priv->mutex);
 1258     {
 1259         list_for_each_entry_safe(clnt, tmp, &priv->client_list, client_list)
 1260         {
 1261             if ((strcmp(clnt->client_uid, client_uid) == 0)) {
 1262                 list_for_each_entry_safe(l_inode, tmp1, &clnt->inode_list, list)
 1263                 {
 1264                     list_del_init(&l_inode->list);
 1265                     list_add_tail(&l_inode->list, &cleanup_list);
 1266                 }
 1267                 __destroy_lease_client(clnt);
 1268                 break;
 1269             }
 1270         }
 1271     }
 1272     pthread_mutex_unlock(&priv->mutex);
 1273 
 1274     l_inode = tmp1 = NULL;
 1275     list_for_each_entry_safe(l_inode, tmp1, &cleanup_list, list)
 1276     {
 1277         remove_clnt_leases(client_uid, l_inode->inode, this);
 1278         __destroy_lease_inode(l_inode);
 1279     }
 1280 out:
 1281     return ret;
 1282 }
 1283 
 1284 static void
 1285 __remove_all_leases(xlator_t *this, lease_inode_ctx_t *lease_ctx)
 1286 {
 1287     int i = 0;
 1288     lease_id_entry_t *lease_entry = NULL;
 1289     lease_id_entry_t *tmp = NULL;
 1290 
 1291     if (lease_ctx->lease_cnt == 0) {
 1292         /* No leases to remove. Return */
 1293         return;
 1294     }
 1295     __dump_leases_info(this, lease_ctx);
 1296 
 1297     list_for_each_entry_safe(lease_entry, tmp, &lease_ctx->lease_id_list,
 1298                              lease_id_list)
 1299     {
 1300         lease_entry->lease_cnt = 0;
 1301         remove_from_clnt_list(this, lease_entry->client_uid, lease_ctx->inode);
 1302         __destroy_lease_id_entry(lease_entry);
 1303     }
 1304     INIT_LIST_HEAD(&lease_ctx->lease_id_list);
 1305     for (i = 0; i <= GF_LEASE_MAX_TYPE; i++)
 1306         lease_ctx->lease_type_cnt[i] = 0;
 1307     lease_ctx->lease_type = 0;
 1308     lease_ctx->lease_cnt = 0;
 1309     lease_ctx->recall_in_progress = _gf_false;
 1310     lease_ctx->timer = NULL;
 1311     lease_ctx->blocked_fops_resuming = _gf_true;
 1312 
 1313     /* TODO:
 1314      * - Mark the corresponding fd bad. Could be done on client side
 1315      * as a result of recall
 1316      * - Free the lease_ctx
 1317      */
 1318     return;
 1319 }
 1320 
 1321 static int
 1322 remove_all_leases(xlator_t *this, inode_t *inode)
 1323 {
 1324     lease_inode_ctx_t *lease_ctx = NULL;
 1325     int ret = 0;
 1326 
 1327     GF_VALIDATE_OR_GOTO("leases", inode, out);
 1328 
 1329     lease_ctx = lease_ctx_get(inode, this);
 1330     if (!lease_ctx) {
 1331         gf_msg(this->name, GF_LOG_WARNING, ENOMEM, LEASE_MSG_INVAL_INODE_CTX,
 1332                "Unable to create/get inode ctx");
 1333         ret = -1;
 1334         errno = ENOMEM;
 1335         goto out;
 1336     }
 1337 
 1338     pthread_mutex_lock(&lease_ctx->lock);
 1339     {
 1340         __remove_all_leases(this, lease_ctx);
 1341     }
 1342     pthread_mutex_unlock(&lease_ctx->lock);
 1343 
 1344     do_blocked_fops(this, lease_ctx);
 1345 out:
 1346     return ret;
 1347 }
 1348 
 1349 void *
 1350 expired_recall_cleanup(void *data)
 1351 {
 1352     struct timespec sleep_till = {
 1353         0,
 1354     };
 1355     struct list_head recall_cleanup_list;
 1356     lease_inode_t *recall_entry = NULL;
 1357     lease_inode_t *tmp = NULL;
 1358     leases_private_t *priv = NULL;
 1359     xlator_t *this = NULL;
 1360     time_t time_now;
 1361 
 1362     GF_VALIDATE_OR_GOTO("leases", data, out);
 1363 
 1364     this = data;
 1365     priv = this->private;
 1366 
 1367     gf_msg_debug(this->name, 0, "Started the expired_recall_cleanup thread");
 1368 
 1369     while (1) {
 1370         time_now = time(NULL);
 1371         pthread_mutex_lock(&priv->mutex);
 1372         {
 1373             if (priv->fini) {
 1374                 pthread_mutex_unlock(&priv->mutex);
 1375                 goto out;
 1376             }
 1377             INIT_LIST_HEAD(&recall_cleanup_list);
 1378             if (list_empty(&priv->recall_list)) {
 1379                 sleep_till.tv_sec = time_now + 600;
 1380                 pthread_cond_timedwait(&priv->cond, &priv->mutex, &sleep_till);
 1381             }
 1382             if (!list_empty(&priv->recall_list)) {
 1383                 gf_msg_debug(this->name, 0, "Found expired recalls");
 1384                 list_for_each_entry_safe(recall_entry, tmp, &priv->recall_list,
 1385                                          list)
 1386                 {
 1387                     list_del_init(&recall_entry->list);
 1388                     list_add_tail(&recall_entry->list, &recall_cleanup_list);
 1389                 }
 1390             }
 1391         }
 1392         pthread_mutex_unlock(&priv->mutex);
 1393 
 1394         recall_entry = tmp = NULL;
 1395         list_for_each_entry_safe(recall_entry, tmp, &recall_cleanup_list, list)
 1396         {
 1397             gf_msg_debug(this->name, 0,
 1398                          "Recall lease was sent on"
 1399                          " inode:%p, recall timer has expired"
 1400                          " and clients haven't unlocked the lease"
 1401                          " hence cleaning up leases on the inode",
 1402                          recall_entry->inode);
 1403             remove_all_leases(this, recall_entry->inode);
 1404             /* no need to take priv->mutex lock as this entry
 1405              * reference is removed from global recall list. */
 1406             __destroy_lease_inode(recall_entry);
 1407         }
 1408     }
 1409 
 1410 out:
 1411     return NULL;
 1412 }