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