"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.2/libglusterfs/src/fd.c" (16 Sep 2020, 28170 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 "fd.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 7.6_vs_7.7.

    1 /*
    2   Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
    3   This file is part of GlusterFS.
    4 
    5   This file is licensed to you under your choice of the GNU Lesser
    6   General Public License, version 3 or any later version (LGPLv3 or
    7   later), or the GNU General Public License, version 2 (GPLv2), in all
    8   cases as published by the Free Software Foundation.
    9 */
   10 
   11 #include "glusterfs/fd.h"
   12 #include <errno.h>     // for EINVAL, errno, ENOMEM
   13 #include <inttypes.h>  // for PRIu64
   14 #include <stdint.h>    // for UINT32_MAX
   15 #include <string.h>    // for NULL, memcpy, memset, size_t
   16 #include "glusterfs/statedump.h"
   17 
   18 static int
   19 gf_fd_fdtable_expand(fdtable_t *fdtable, uint32_t nr);
   20 
   21 fd_t *
   22 __fd_ref(fd_t *fd);
   23 
   24 static int
   25 gf_fd_chain_fd_entries(fdentry_t *entries, uint32_t startidx, uint32_t endcount)
   26 {
   27     uint32_t i = 0;
   28 
   29     if (!entries) {
   30         gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
   31                          "!entries");
   32         return -1;
   33     }
   34 
   35     /* Chain only till the second to last entry because we want to
   36      * ensure that the last entry has GF_FDTABLE_END.
   37      */
   38     for (i = startidx; i < (endcount - 1); i++)
   39         entries[i].next_free = i + 1;
   40 
   41     /* i has already been incremented up to the last entry. */
   42     entries[i].next_free = GF_FDTABLE_END;
   43 
   44     return 0;
   45 }
   46 
   47 static int
   48 gf_fd_fdtable_expand(fdtable_t *fdtable, uint32_t nr)
   49 {
   50     fdentry_t *oldfds = NULL;
   51     uint32_t oldmax_fds = -1;
   52     int ret = -1;
   53 
   54     if (fdtable == NULL || nr > UINT32_MAX) {
   55         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
   56                          "invalid argument");
   57         ret = EINVAL;
   58         goto out;
   59     }
   60 
   61     nr /= (1024 / sizeof(fdentry_t));
   62     nr = gf_roundup_next_power_of_two(nr + 1);
   63     nr *= (1024 / sizeof(fdentry_t));
   64 
   65     oldfds = fdtable->fdentries;
   66     oldmax_fds = fdtable->max_fds;
   67 
   68     fdtable->fdentries = GF_CALLOC(nr, sizeof(fdentry_t),
   69                                    gf_common_mt_fdentry_t);
   70     if (!fdtable->fdentries) {
   71         ret = ENOMEM;
   72         goto out;
   73     }
   74     fdtable->max_fds = nr;
   75 
   76     if (oldfds) {
   77         uint32_t cpy = oldmax_fds * sizeof(fdentry_t);
   78         memcpy(fdtable->fdentries, oldfds, cpy);
   79     }
   80 
   81     gf_fd_chain_fd_entries(fdtable->fdentries, oldmax_fds, fdtable->max_fds);
   82 
   83     /* Now that expansion is done, we must update the fd list
   84      * head pointer so that the fd allocation functions can continue
   85      * using the expanded table.
   86      */
   87     fdtable->first_free = oldmax_fds;
   88     GF_FREE(oldfds);
   89     ret = 0;
   90 out:
   91     return ret;
   92 }
   93 
   94 fdtable_t *
   95 gf_fd_fdtable_alloc(void)
   96 {
   97     fdtable_t *fdtable = NULL;
   98 
   99     fdtable = GF_CALLOC(1, sizeof(*fdtable), gf_common_mt_fdtable_t);
  100     if (!fdtable)
  101         return NULL;
  102 
  103     pthread_rwlock_init(&fdtable->lock, NULL);
  104 
  105     pthread_rwlock_wrlock(&fdtable->lock);
  106     {
  107         gf_fd_fdtable_expand(fdtable, 0);
  108     }
  109     pthread_rwlock_unlock(&fdtable->lock);
  110 
  111     return fdtable;
  112 }
  113 
  114 static fdentry_t *
  115 __gf_fd_fdtable_get_all_fds(fdtable_t *fdtable, uint32_t *count)
  116 {
  117     fdentry_t *fdentries = NULL;
  118 
  119     if (count == NULL) {
  120         gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
  121                          "!count");
  122         goto out;
  123     }
  124 
  125     fdentries = fdtable->fdentries;
  126     fdtable->fdentries = GF_CALLOC(fdtable->max_fds, sizeof(fdentry_t),
  127                                    gf_common_mt_fdentry_t);
  128     gf_fd_chain_fd_entries(fdtable->fdentries, 0, fdtable->max_fds);
  129     *count = fdtable->max_fds;
  130 
  131 out:
  132     return fdentries;
  133 }
  134 
  135 fdentry_t *
  136 gf_fd_fdtable_get_all_fds(fdtable_t *fdtable, uint32_t *count)
  137 {
  138     fdentry_t *entries = NULL;
  139 
  140     if (fdtable) {
  141         pthread_rwlock_wrlock(&fdtable->lock);
  142         {
  143             entries = __gf_fd_fdtable_get_all_fds(fdtable, count);
  144         }
  145         pthread_rwlock_unlock(&fdtable->lock);
  146     }
  147 
  148     return entries;
  149 }
  150 
  151 static fdentry_t *
  152 __gf_fd_fdtable_copy_all_fds(fdtable_t *fdtable, uint32_t *count)
  153 {
  154     fdentry_t *fdentries = NULL;
  155     int i = 0;
  156 
  157     if (count == NULL) {
  158         gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
  159                          "!count");
  160         goto out;
  161     }
  162 
  163     fdentries = GF_CALLOC(fdtable->max_fds, sizeof(fdentry_t),
  164                           gf_common_mt_fdentry_t);
  165     if (fdentries == NULL) {
  166         goto out;
  167     }
  168 
  169     *count = fdtable->max_fds;
  170 
  171     for (i = 0; i < fdtable->max_fds; i++) {
  172         if (fdtable->fdentries[i].fd != NULL) {
  173             fdentries[i].fd = fd_ref(fdtable->fdentries[i].fd);
  174         }
  175     }
  176 
  177 out:
  178     return fdentries;
  179 }
  180 
  181 fdentry_t *
  182 gf_fd_fdtable_copy_all_fds(fdtable_t *fdtable, uint32_t *count)
  183 {
  184     fdentry_t *entries = NULL;
  185 
  186     if (fdtable) {
  187         pthread_rwlock_rdlock(&fdtable->lock);
  188         {
  189             entries = __gf_fd_fdtable_copy_all_fds(fdtable, count);
  190         }
  191         pthread_rwlock_unlock(&fdtable->lock);
  192     }
  193 
  194     return entries;
  195 }
  196 
  197 void
  198 gf_fd_fdtable_destroy(fdtable_t *fdtable)
  199 {
  200     struct list_head list = {
  201         0,
  202     };
  203     fd_t *fd = NULL;
  204     fdentry_t *fdentries = NULL;
  205     uint32_t fd_count = 0;
  206     int32_t i = 0;
  207 
  208     INIT_LIST_HEAD(&list);
  209 
  210     if (!fdtable) {
  211         gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
  212                          "!fdtable");
  213         return;
  214     }
  215 
  216     pthread_rwlock_wrlock(&fdtable->lock);
  217     {
  218         fdentries = __gf_fd_fdtable_get_all_fds(fdtable, &fd_count);
  219         GF_FREE(fdtable->fdentries);
  220     }
  221     pthread_rwlock_unlock(&fdtable->lock);
  222 
  223     if (fdentries != NULL) {
  224         for (i = 0; i < fd_count; i++) {
  225             fd = fdentries[i].fd;
  226             if (fd != NULL) {
  227                 fd_unref(fd);
  228             }
  229         }
  230 
  231         GF_FREE(fdentries);
  232         pthread_rwlock_destroy(&fdtable->lock);
  233         GF_FREE(fdtable);
  234     }
  235 }
  236 
  237 int
  238 gf_fd_unused_get(fdtable_t *fdtable, fd_t *fdptr)
  239 {
  240     int32_t fd = -1;
  241     fdentry_t *fde = NULL;
  242     int error;
  243     int alloc_attempts = 0;
  244 
  245     if (fdtable == NULL || fdptr == NULL) {
  246         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  247                          "invalid argument");
  248         return EINVAL;
  249     }
  250 
  251     pthread_rwlock_wrlock(&fdtable->lock);
  252     {
  253     fd_alloc_try_again:
  254         if (fdtable->first_free != GF_FDTABLE_END) {
  255             fde = &fdtable->fdentries[fdtable->first_free];
  256             fd = fdtable->first_free;
  257             fdtable->first_free = fde->next_free;
  258             fde->next_free = GF_FDENTRY_ALLOCATED;
  259             fde->fd = fdptr;
  260         } else {
  261             /* If this is true, there is something
  262              * seriously wrong with our data structures.
  263              */
  264             if (alloc_attempts >= 2) {
  265                 gf_msg("fd", GF_LOG_ERROR, 0, LG_MSG_EXPAND_FD_TABLE_FAILED,
  266                        "multiple attempts to expand fd table"
  267                        " have failed.");
  268                 goto out;
  269             }
  270             error = gf_fd_fdtable_expand(fdtable, fdtable->max_fds + 1);
  271             if (error) {
  272                 gf_msg("fd", GF_LOG_ERROR, error, LG_MSG_EXPAND_FD_TABLE_FAILED,
  273                        "Cannot expand fdtable");
  274                 goto out;
  275             }
  276             ++alloc_attempts;
  277             /* At this point, the table stands expanded
  278              * with the first_free referring to the first
  279              * free entry in the new set of fdentries that
  280              * have just been allocated. That means, the
  281              * above logic should just work.
  282              */
  283             goto fd_alloc_try_again;
  284         }
  285     }
  286 out:
  287     pthread_rwlock_unlock(&fdtable->lock);
  288 
  289     return fd;
  290 }
  291 
  292 void
  293 gf_fd_put(fdtable_t *fdtable, int32_t fd)
  294 {
  295     fd_t *fdptr = NULL;
  296     fdentry_t *fde = NULL;
  297 
  298     if (fd == GF_ANON_FD_NO)
  299         return;
  300 
  301     if (fdtable == NULL || fd < 0) {
  302         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  303                          "invalid argument");
  304         return;
  305     }
  306 
  307     if (!(fd < fdtable->max_fds)) {
  308         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  309                          "invalid argument");
  310         return;
  311     }
  312 
  313     pthread_rwlock_wrlock(&fdtable->lock);
  314     {
  315         fde = &fdtable->fdentries[fd];
  316         /* If the entry is not allocated, put operation must return
  317          * without doing anything.
  318          * This has the potential of masking out any bugs in a user of
  319          * fd that ends up calling gf_fd_put twice for the same fd or
  320          * for an unallocated fd, but it is a price we have to pay for
  321          * ensuring sanity of our fd-table.
  322          */
  323         if (fde->next_free != GF_FDENTRY_ALLOCATED)
  324             goto unlock_out;
  325         fdptr = fde->fd;
  326         fde->fd = NULL;
  327         fde->next_free = fdtable->first_free;
  328         fdtable->first_free = fd;
  329     }
  330 unlock_out:
  331     pthread_rwlock_unlock(&fdtable->lock);
  332 
  333     if (fdptr) {
  334         fd_unref(fdptr);
  335     }
  336 }
  337 
  338 void
  339 gf_fdptr_put(fdtable_t *fdtable, fd_t *fd)
  340 {
  341     fdentry_t *fde = NULL;
  342     int32_t i = 0;
  343 
  344     if ((fdtable == NULL) || (fd == NULL)) {
  345         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  346                          "invalid argument");
  347         return;
  348     }
  349 
  350     pthread_rwlock_wrlock(&fdtable->lock);
  351     {
  352         for (i = 0; i < fdtable->max_fds; i++) {
  353             if (fdtable->fdentries[i].fd == fd) {
  354                 fde = &fdtable->fdentries[i];
  355                 break;
  356             }
  357         }
  358 
  359         if (fde == NULL) {
  360             gf_msg_callingfn("fd", GF_LOG_WARNING, 0,
  361                              LG_MSG_FD_NOT_FOUND_IN_FDTABLE,
  362                              "fd (%p) is not present in fdtable", fd);
  363             goto unlock_out;
  364         }
  365 
  366         /* If the entry is not allocated, put operation must return
  367          * without doing anything.
  368          * This has the potential of masking out any bugs in a user of
  369          * fd that ends up calling gf_fd_put twice for the same fd or
  370          * for an unallocated fd, but it is a price we have to pay for
  371          * ensuring sanity of our fd-table.
  372          */
  373         if (fde->next_free != GF_FDENTRY_ALLOCATED)
  374             goto unlock_out;
  375         fde->fd = NULL;
  376         fde->next_free = fdtable->first_free;
  377         fdtable->first_free = i;
  378     }
  379 unlock_out:
  380     pthread_rwlock_unlock(&fdtable->lock);
  381 
  382     if ((fd != NULL) && (fde != NULL)) {
  383         fd_unref(fd);
  384     }
  385 }
  386 
  387 fd_t *
  388 gf_fd_fdptr_get(fdtable_t *fdtable, int64_t fd)
  389 {
  390     fd_t *fdptr = NULL;
  391 
  392     if (fdtable == NULL || fd < 0) {
  393         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  394                          "invalid argument");
  395         errno = EINVAL;
  396         return NULL;
  397     }
  398 
  399     if (!(fd < fdtable->max_fds)) {
  400         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  401                          "invalid argument");
  402         errno = EINVAL;
  403         return NULL;
  404     }
  405 
  406     pthread_rwlock_rdlock(&fdtable->lock);
  407     {
  408         fdptr = fdtable->fdentries[fd].fd;
  409         if (fdptr) {
  410             fd_ref(fdptr);
  411         }
  412     }
  413     pthread_rwlock_unlock(&fdtable->lock);
  414 
  415     return fdptr;
  416 }
  417 
  418 fd_t *
  419 __fd_ref(fd_t *fd)
  420 {
  421     GF_ATOMIC_INC(fd->refcount);
  422 
  423     return fd;
  424 }
  425 
  426 fd_t *
  427 fd_ref(fd_t *fd)
  428 {
  429     if (!fd) {
  430         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  431                          "null fd");
  432         return NULL;
  433     }
  434 
  435     GF_ATOMIC_INC(fd->refcount);
  436 
  437     return fd;
  438 }
  439 
  440 static void
  441 fd_destroy(fd_t *fd, gf_boolean_t bound)
  442 {
  443     xlator_t *xl = NULL;
  444     int i = 0;
  445     xlator_t *old_THIS = NULL;
  446 
  447     if (fd == NULL) {
  448         gf_msg_callingfn("xlator", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  449                          "invalid argument");
  450         goto out;
  451     }
  452 
  453     if (fd->inode == NULL) {
  454         gf_msg_callingfn("xlator", GF_LOG_ERROR, 0, LG_MSG_FD_INODE_NULL,
  455                          "fd->inode is NULL");
  456         goto out;
  457     }
  458     if (!fd->_ctx)
  459         goto out;
  460 
  461     if (IA_ISDIR(fd->inode->ia_type)) {
  462         for (i = 0; i < fd->xl_count; i++) {
  463             if (fd->_ctx[i].key) {
  464                 xl = fd->_ctx[i].xl_key;
  465                 old_THIS = THIS;
  466                 THIS = xl;
  467                 if (!xl->call_cleanup && xl->cbks->releasedir)
  468                     xl->cbks->releasedir(xl, fd);
  469                 THIS = old_THIS;
  470             }
  471         }
  472     } else {
  473         for (i = 0; i < fd->xl_count; i++) {
  474             if (fd->_ctx[i].key) {
  475                 xl = fd->_ctx[i].xl_key;
  476                 old_THIS = THIS;
  477                 THIS = xl;
  478                 if (!xl->call_cleanup && xl->cbks->release)
  479                     xl->cbks->release(xl, fd);
  480                 THIS = old_THIS;
  481             }
  482         }
  483     }
  484 
  485     LOCK_DESTROY(&fd->lock);
  486 
  487     GF_FREE(fd->_ctx);
  488     if (bound) {
  489         /*Decrease the count only after close happens on file*/
  490         LOCK(&fd->inode->lock);
  491         {
  492             fd->inode->fd_count--;
  493         }
  494         UNLOCK(&fd->inode->lock);
  495     }
  496     inode_unref(fd->inode);
  497     fd->inode = NULL;
  498     fd_lk_ctx_unref(fd->lk_ctx);
  499     mem_put(fd);
  500 out:
  501     return;
  502 }
  503 
  504 void
  505 fd_close(fd_t *fd)
  506 {
  507     xlator_t *xl, *old_THIS;
  508 
  509     old_THIS = THIS;
  510 
  511     for (xl = fd->inode->table->xl->graph->first; xl != NULL; xl = xl->next) {
  512         if (!xl->call_cleanup) {
  513             THIS = xl;
  514 
  515             if (IA_ISDIR(fd->inode->ia_type)) {
  516                 if (xl->cbks->fdclosedir != NULL) {
  517                     xl->cbks->fdclosedir(xl, fd);
  518                 }
  519             } else {
  520                 if (xl->cbks->fdclose != NULL) {
  521                     xl->cbks->fdclose(xl, fd);
  522                 }
  523             }
  524         }
  525     }
  526 
  527     THIS = old_THIS;
  528 }
  529 
  530 void
  531 fd_unref(fd_t *fd)
  532 {
  533     int32_t refcount = 0;
  534     gf_boolean_t bound = _gf_false;
  535 
  536     if (!fd) {
  537         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  538                          "fd is NULL");
  539         return;
  540     }
  541 
  542     LOCK(&fd->inode->lock);
  543     {
  544         refcount = GF_ATOMIC_DEC(fd->refcount);
  545         if (refcount == 0) {
  546             if (!list_empty(&fd->inode_list)) {
  547                 list_del_init(&fd->inode_list);
  548                 fd->inode->active_fd_count--;
  549                 bound = _gf_true;
  550             }
  551         }
  552     }
  553     UNLOCK(&fd->inode->lock);
  554 
  555     if (refcount == 0) {
  556         fd_destroy(fd, bound);
  557     }
  558 
  559     return;
  560 }
  561 
  562 static fd_t *
  563 __fd_bind(fd_t *fd)
  564 {
  565     list_del_init(&fd->inode_list);
  566     list_add(&fd->inode_list, &fd->inode->fd_list);
  567     fd->inode->fd_count++;
  568     fd->inode->active_fd_count++;
  569 
  570     return fd;
  571 }
  572 
  573 fd_t *
  574 fd_bind(fd_t *fd)
  575 {
  576     if (!fd || !fd->inode) {
  577         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  578                          "!fd || !fd->inode");
  579         return NULL;
  580     }
  581 
  582     LOCK(&fd->inode->lock);
  583     {
  584         fd = __fd_bind(fd);
  585     }
  586     UNLOCK(&fd->inode->lock);
  587 
  588     return fd;
  589 }
  590 
  591 static fd_t *
  592 fd_allocate(inode_t *inode, uint64_t pid)
  593 {
  594     fd_t *fd;
  595 
  596     if (inode == NULL) {
  597         gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
  598                          "invalid argument");
  599         return NULL;
  600     }
  601 
  602     fd = mem_get0(inode->table->fd_mem_pool);
  603     if (fd == NULL) {
  604         return NULL;
  605     }
  606 
  607     fd->xl_count = inode->table->xl->graph->xl_count + 1;
  608 
  609     fd->_ctx = GF_CALLOC(1, (sizeof(struct _fd_ctx) * fd->xl_count),
  610                          gf_common_mt_fd_ctx);
  611     if (fd->_ctx == NULL) {
  612         goto failed;
  613     }
  614 
  615     fd->lk_ctx = fd_lk_ctx_create();
  616     if (fd->lk_ctx != NULL) {
  617         /* We need to take a reference from the inode, but we cannot do it
  618          * here because this function can be called with the inode lock taken
  619          * and inode_ref() takes the inode's table lock. This is the reverse
  620          * of the logical lock acquisition order and can cause a deadlock. So
  621          * we simply assign the inode here and we delefate the inode reference
  622          * responsibility to the caller (when this function succeeds and the
  623          * inode lock is released). This is safe because the caller must hold
  624          * a reference of the inode to use it, so it's guaranteed that the
  625          * number of references won't reach 0 before the caller finishes.
  626          *
  627          * TODO: minimize use of locks in favor of atomic operations to avoid
  628          *       these dependencies. */
  629         fd->inode = inode;
  630         fd->pid = pid;
  631         INIT_LIST_HEAD(&fd->inode_list);
  632         LOCK_INIT(&fd->lock);
  633         GF_ATOMIC_INIT(fd->refcount, 1);
  634         return fd;
  635     }
  636 
  637     GF_FREE(fd->_ctx);
  638 
  639 failed:
  640     mem_put(fd);
  641 
  642     return NULL;
  643 }
  644 
  645 fd_t *
  646 fd_create_uint64(inode_t *inode, uint64_t pid)
  647 {
  648     fd_t *fd;
  649 
  650     fd = fd_allocate(inode, pid);
  651     if (fd != NULL) {
  652         /* fd_allocate() doesn't get a reference from the inode. We need to
  653          * take it here in case of success. */
  654         inode_ref(inode);
  655     }
  656 
  657     return fd;
  658 }
  659 
  660 fd_t *
  661 fd_create(inode_t *inode, pid_t pid)
  662 {
  663     return fd_create_uint64(inode, (uint64_t)pid);
  664 }
  665 
  666 static fd_t *
  667 __fd_lookup(inode_t *inode, uint64_t pid)
  668 {
  669     fd_t *iter_fd = NULL;
  670     fd_t *fd = NULL;
  671 
  672     if (list_empty(&inode->fd_list))
  673         return NULL;
  674 
  675     list_for_each_entry(iter_fd, &inode->fd_list, inode_list)
  676     {
  677         if (iter_fd->anonymous)
  678             /* If someone was interested in getting an
  679                anonymous fd (or was OK getting an anonymous fd),
  680                they can as well call fd_anonymous() directly */
  681             continue;
  682 
  683         if (!pid || iter_fd->pid == pid) {
  684             fd = __fd_ref(iter_fd);
  685             break;
  686         }
  687     }
  688 
  689     return fd;
  690 }
  691 
  692 fd_t *
  693 fd_lookup(inode_t *inode, pid_t pid)
  694 {
  695     fd_t *fd = NULL;
  696 
  697     if (!inode) {
  698         gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
  699                          "!inode");
  700         return NULL;
  701     }
  702 
  703     LOCK(&inode->lock);
  704     {
  705         fd = __fd_lookup(inode, (uint64_t)pid);
  706     }
  707     UNLOCK(&inode->lock);
  708 
  709     return fd;
  710 }
  711 
  712 fd_t *
  713 fd_lookup_uint64(inode_t *inode, uint64_t pid)
  714 {
  715     fd_t *fd = NULL;
  716 
  717     if (!inode) {
  718         gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
  719                          "!inode");
  720         return NULL;
  721     }
  722 
  723     LOCK(&inode->lock);
  724     {
  725         fd = __fd_lookup(inode, pid);
  726     }
  727     UNLOCK(&inode->lock);
  728 
  729     return fd;
  730 }
  731 
  732 static fd_t *
  733 __fd_lookup_anonymous(inode_t *inode, int32_t flags)
  734 {
  735     fd_t *iter_fd = NULL;
  736     fd_t *fd = NULL;
  737 
  738     if (list_empty(&inode->fd_list))
  739         return NULL;
  740 
  741     list_for_each_entry(iter_fd, &inode->fd_list, inode_list)
  742     {
  743         if ((iter_fd->anonymous) && (flags == iter_fd->flags)) {
  744             fd = __fd_ref(iter_fd);
  745             break;
  746         }
  747     }
  748 
  749     return fd;
  750 }
  751 
  752 fd_t *
  753 fd_anonymous_with_flags(inode_t *inode, int32_t flags)
  754 {
  755     fd_t *fd = NULL;
  756     bool ref = false;
  757 
  758     LOCK(&inode->lock);
  759 
  760     fd = __fd_lookup_anonymous(inode, flags);
  761 
  762     /* if (fd); then we already have increased the refcount in
  763        __fd_lookup_anonymous(), so no need of one more fd_ref().
  764        if (!fd); then both create and bind won't bump up the ref
  765        count, so we have to call fd_ref() after bind. */
  766     if (fd == NULL) {
  767         fd = fd_allocate(inode, 0);
  768         if (fd != NULL) {
  769             fd->anonymous = _gf_true;
  770             fd->flags = GF_ANON_FD_FLAGS | (flags & O_DIRECT);
  771 
  772             __fd_bind(fd);
  773 
  774             ref = true;
  775         }
  776     }
  777 
  778     UNLOCK(&inode->lock);
  779 
  780     if (ref) {
  781         /* fd_allocate() doesn't get a reference from the inode. We need to
  782          * take it here in case of success. */
  783         inode_ref(inode);
  784     }
  785 
  786     return fd;
  787 }
  788 
  789 fd_t *
  790 fd_anonymous(inode_t *inode)
  791 {
  792     return fd_anonymous_with_flags(inode, 0);
  793 }
  794 
  795 fd_t *
  796 fd_lookup_anonymous(inode_t *inode, int32_t flags)
  797 {
  798     fd_t *fd = NULL;
  799 
  800     if (!inode) {
  801         gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
  802                          "!inode");
  803         return NULL;
  804     }
  805 
  806     LOCK(&inode->lock);
  807     {
  808         fd = __fd_lookup_anonymous(inode, flags);
  809     }
  810     UNLOCK(&inode->lock);
  811     return fd;
  812 }
  813 
  814 gf_boolean_t
  815 fd_is_anonymous(fd_t *fd)
  816 {
  817     return (fd && fd->anonymous);
  818 }
  819 
  820 uint8_t
  821 fd_list_empty(inode_t *inode)
  822 {
  823     uint8_t empty = 0;
  824 
  825     LOCK(&inode->lock);
  826     {
  827         empty = list_empty(&inode->fd_list);
  828     }
  829     UNLOCK(&inode->lock);
  830 
  831     return empty;
  832 }
  833 
  834 int
  835 __fd_ctx_set(fd_t *fd, xlator_t *xlator, uint64_t value)
  836 {
  837     int index = 0, new_xl_count = 0;
  838     int ret = 0;
  839     int set_idx = -1;
  840     void *begin = NULL;
  841     size_t diff = 0;
  842     struct _fd_ctx *tmp = NULL;
  843 
  844     if (!fd || !xlator)
  845         return -1;
  846 
  847     for (index = 0; index < fd->xl_count; index++) {
  848         if (!fd->_ctx[index].key) {
  849             if (set_idx == -1)
  850                 set_idx = index;
  851             /* don't break, to check if key already exists
  852                further on */
  853         }
  854         if (fd->_ctx[index].xl_key == xlator) {
  855             set_idx = index;
  856             break;
  857         }
  858     }
  859 
  860     if (set_idx == -1) {
  861         set_idx = fd->xl_count;
  862 
  863         new_xl_count = fd->xl_count + xlator->graph->xl_count;
  864 
  865         tmp = GF_REALLOC(fd->_ctx, (sizeof(struct _fd_ctx) * new_xl_count));
  866         if (tmp == NULL) {
  867             ret = -1;
  868             goto out;
  869         }
  870 
  871         fd->_ctx = tmp;
  872 
  873         begin = fd->_ctx;
  874         begin += (fd->xl_count * sizeof(struct _fd_ctx));
  875 
  876         diff = (new_xl_count - fd->xl_count) * sizeof(struct _fd_ctx);
  877 
  878         memset(begin, 0, diff);
  879 
  880         fd->xl_count = new_xl_count;
  881     }
  882 
  883     fd->_ctx[set_idx].xl_key = xlator;
  884     fd->_ctx[set_idx].value1 = value;
  885 
  886 out:
  887     return ret;
  888 }
  889 
  890 int
  891 fd_ctx_set(fd_t *fd, xlator_t *xlator, uint64_t value)
  892 {
  893     int ret = 0;
  894 
  895     if (!fd || !xlator) {
  896         gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
  897                          "%p %p", fd, xlator);
  898         return -1;
  899     }
  900 
  901     LOCK(&fd->lock);
  902     {
  903         ret = __fd_ctx_set(fd, xlator, value);
  904     }
  905     UNLOCK(&fd->lock);
  906 
  907     return ret;
  908 }
  909 
  910 int
  911 __fd_ctx_get(fd_t *fd, xlator_t *xlator, uint64_t *value)
  912 {
  913     int index = 0;
  914     int ret = 0;
  915 
  916     if (!fd || !xlator)
  917         return -1;
  918 
  919     for (index = 0; index < fd->xl_count; index++) {
  920         if (fd->_ctx[index].xl_key == xlator)
  921             break;
  922     }
  923 
  924     if (index == fd->xl_count) {
  925         ret = -1;
  926         goto out;
  927     }
  928 
  929     if (value)
  930         *value = fd->_ctx[index].value1;
  931 
  932 out:
  933     return ret;
  934 }
  935 
  936 int
  937 fd_ctx_get(fd_t *fd, xlator_t *xlator, uint64_t *value)
  938 {
  939     int ret = 0;
  940 
  941     if (!fd || !xlator)
  942         return -1;
  943 
  944     LOCK(&fd->lock);
  945     {
  946         ret = __fd_ctx_get(fd, xlator, value);
  947     }
  948     UNLOCK(&fd->lock);
  949 
  950     return ret;
  951 }
  952 
  953 int
  954 __fd_ctx_del(fd_t *fd, xlator_t *xlator, uint64_t *value)
  955 {
  956     int index = 0;
  957     int ret = 0;
  958 
  959     if (!fd || !xlator)
  960         return -1;
  961 
  962     for (index = 0; index < fd->xl_count; index++) {
  963         if (fd->_ctx[index].xl_key == xlator)
  964             break;
  965     }
  966 
  967     if (index == fd->xl_count) {
  968         ret = -1;
  969         goto out;
  970     }
  971 
  972     if (value)
  973         *value = fd->_ctx[index].value1;
  974 
  975     fd->_ctx[index].key = 0;
  976     fd->_ctx[index].value1 = 0;
  977 
  978 out:
  979     return ret;
  980 }
  981 
  982 int
  983 fd_ctx_del(fd_t *fd, xlator_t *xlator, uint64_t *value)
  984 {
  985     int ret = 0;
  986 
  987     if (!fd || !xlator)
  988         return -1;
  989 
  990     LOCK(&fd->lock);
  991     {
  992         ret = __fd_ctx_del(fd, xlator, value);
  993     }
  994     UNLOCK(&fd->lock);
  995 
  996     return ret;
  997 }
  998 
  999 void
 1000 fd_dump(fd_t *fd, char *prefix)
 1001 {
 1002     char key[GF_DUMP_MAX_BUF_LEN];
 1003 
 1004     if (!fd)
 1005         return;
 1006 
 1007     gf_proc_dump_write("pid", "%" PRIu64, fd->pid);
 1008     gf_proc_dump_write("refcount", "%" GF_PRI_ATOMIC,
 1009                        GF_ATOMIC_GET(fd->refcount));
 1010     gf_proc_dump_write("flags", "%d", fd->flags);
 1011 
 1012     if (fd->inode) {
 1013         gf_proc_dump_build_key(key, "inode", NULL);
 1014         gf_proc_dump_add_section("%s", key);
 1015         inode_dump(fd->inode, key);
 1016     }
 1017 }
 1018 
 1019 void
 1020 fdentry_dump(fdentry_t *fdentry, char *prefix)
 1021 {
 1022     if (!fdentry)
 1023         return;
 1024 
 1025     if (GF_FDENTRY_ALLOCATED != fdentry->next_free)
 1026         return;
 1027 
 1028     if (fdentry->fd)
 1029         fd_dump(fdentry->fd, prefix);
 1030 }
 1031 
 1032 void
 1033 fdtable_dump(fdtable_t *fdtable, char *prefix)
 1034 {
 1035     char key[GF_DUMP_MAX_BUF_LEN];
 1036     int i = 0;
 1037     int ret = -1;
 1038 
 1039     if (!fdtable)
 1040         return;
 1041 
 1042     ret = pthread_rwlock_tryrdlock(&fdtable->lock);
 1043     if (ret)
 1044         goto out;
 1045 
 1046     gf_proc_dump_build_key(key, prefix, "refcount");
 1047     gf_proc_dump_write(key, "%d", fdtable->refcount);
 1048     gf_proc_dump_build_key(key, prefix, "maxfds");
 1049     gf_proc_dump_write(key, "%d", fdtable->max_fds);
 1050     gf_proc_dump_build_key(key, prefix, "first_free");
 1051     gf_proc_dump_write(key, "%d", fdtable->first_free);
 1052 
 1053     for (i = 0; i < fdtable->max_fds; i++) {
 1054         if (GF_FDENTRY_ALLOCATED == fdtable->fdentries[i].next_free) {
 1055             gf_proc_dump_build_key(key, prefix, "fdentry[%d]", i);
 1056             gf_proc_dump_add_section("%s", key);
 1057             fdentry_dump(&fdtable->fdentries[i], key);
 1058         }
 1059     }
 1060 
 1061     pthread_rwlock_unlock(&fdtable->lock);
 1062 
 1063 out:
 1064     if (ret != 0)
 1065         gf_proc_dump_write("Unable to dump the fdtable",
 1066                            "(Lock acquistion failed) %p", fdtable);
 1067     return;
 1068 }
 1069 
 1070 void
 1071 fd_ctx_dump(fd_t *fd, char *prefix)
 1072 {
 1073     struct _fd_ctx *fd_ctx = NULL;
 1074     xlator_t *xl = NULL;
 1075     int i = 0;
 1076 
 1077     if ((fd == NULL) || (fd->_ctx == NULL)) {
 1078         goto out;
 1079     }
 1080 
 1081     LOCK(&fd->lock);
 1082     {
 1083         if (fd->_ctx != NULL) {
 1084             fd_ctx = GF_CALLOC(fd->xl_count, sizeof(*fd_ctx),
 1085                                gf_common_mt_fd_ctx);
 1086             if (fd_ctx == NULL) {
 1087                 goto unlock;
 1088             }
 1089 
 1090             for (i = 0; i < fd->xl_count; i++) {
 1091                 fd_ctx[i] = fd->_ctx[i];
 1092             }
 1093         }
 1094     }
 1095 unlock:
 1096     UNLOCK(&fd->lock);
 1097 
 1098     if (fd_ctx == NULL) {
 1099         goto out;
 1100     }
 1101 
 1102     for (i = 0; i < fd->xl_count; i++) {
 1103         if (fd_ctx[i].xl_key) {
 1104             xl = (xlator_t *)(long)fd_ctx[i].xl_key;
 1105             if (xl->dumpops && xl->dumpops->fdctx)
 1106                 xl->dumpops->fdctx(xl, fd);
 1107         }
 1108     }
 1109 
 1110 out:
 1111     GF_FREE(fd_ctx);
 1112 
 1113     return;
 1114 }
 1115 
 1116 void
 1117 fdentry_dump_to_dict(fdentry_t *fdentry, char *prefix, dict_t *dict,
 1118                      int *openfds)
 1119 {
 1120     char key[GF_DUMP_MAX_BUF_LEN] = {
 1121         0,
 1122     };
 1123     int ret = -1;
 1124 
 1125     if (!fdentry)
 1126         return;
 1127     if (!dict)
 1128         return;
 1129 
 1130     if (GF_FDENTRY_ALLOCATED != fdentry->next_free)
 1131         return;
 1132 
 1133     if (fdentry->fd) {
 1134         snprintf(key, sizeof(key), "%s.pid", prefix);
 1135         ret = dict_set_uint64(dict, key, fdentry->fd->pid);
 1136         if (ret)
 1137             return;
 1138 
 1139         snprintf(key, sizeof(key), "%s.refcount", prefix);
 1140         ret = dict_set_int32(dict, key, GF_ATOMIC_GET(fdentry->fd->refcount));
 1141         if (ret)
 1142             return;
 1143 
 1144         snprintf(key, sizeof(key), "%s.flags", prefix);
 1145         ret = dict_set_int32(dict, key, fdentry->fd->flags);
 1146         if (ret)
 1147             return;
 1148 
 1149         (*openfds)++;
 1150     }
 1151     return;
 1152 }
 1153 
 1154 void
 1155 fdtable_dump_to_dict(fdtable_t *fdtable, char *prefix, dict_t *dict)
 1156 {
 1157     char key[GF_DUMP_MAX_BUF_LEN] = {
 1158         0,
 1159     };
 1160     int i = 0;
 1161     int openfds = 0;
 1162     int ret = -1;
 1163 
 1164     if (!fdtable)
 1165         return;
 1166     if (!dict)
 1167         return;
 1168 
 1169     ret = pthread_rwlock_tryrdlock(&fdtable->lock);
 1170     if (ret)
 1171         return;
 1172 
 1173     snprintf(key, sizeof(key), "%s.fdtable.refcount", prefix);
 1174     ret = dict_set_int32(dict, key, fdtable->refcount);
 1175     if (ret)
 1176         goto out;
 1177 
 1178     snprintf(key, sizeof(key), "%s.fdtable.maxfds", prefix);
 1179     ret = dict_set_uint32(dict, key, fdtable->max_fds);
 1180     if (ret)
 1181         goto out;
 1182 
 1183     snprintf(key, sizeof(key), "%s.fdtable.firstfree", prefix);
 1184     ret = dict_set_int32(dict, key, fdtable->first_free);
 1185     if (ret)
 1186         goto out;
 1187 
 1188     for (i = 0; i < fdtable->max_fds; i++) {
 1189         if (GF_FDENTRY_ALLOCATED == fdtable->fdentries[i].next_free) {
 1190             snprintf(key, sizeof(key), "%s.fdtable.fdentry%d", prefix, i);
 1191             fdentry_dump_to_dict(&fdtable->fdentries[i], key, dict, &openfds);
 1192         }
 1193     }
 1194 
 1195     snprintf(key, sizeof(key), "%s.fdtable.openfds", prefix);
 1196     ret = dict_set_int32(dict, key, openfds);
 1197     if (ret)
 1198         goto out;
 1199 
 1200 out:
 1201     pthread_rwlock_unlock(&fdtable->lock);
 1202     return;
 1203 }