"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-7.6/xlators/mount/fuse/src/fuse-bridge.c" (18 May 2020, 212805 Bytes) of package /linux/misc/glusterfs-7.6.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 "fuse-bridge.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 7.5_vs_7.6.

    1 /*
    2   Copyright (c) 2006-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 <sys/wait.h>
   12 #include "fuse-bridge.h"
   13 #include <glusterfs/glusterfs.h>
   14 #include <glusterfs/byte-order.h>
   15 #include <glusterfs/compat-errno.h>
   16 #include <glusterfs/glusterfs-acl.h>
   17 #include <glusterfs/syscall.h>
   18 #include <glusterfs/timespec.h>
   19 #include <glusterfs/async.h>
   20 
   21 #ifdef __NetBSD__
   22 #undef open /* in perfuse.h, pulled from mount-gluster-compat.h */
   23 #endif
   24 typedef struct _fuse_async {
   25     struct iobuf *iobuf;
   26     fuse_in_header_t *finh;
   27     void *msg;
   28     gf_async_t async;
   29 } fuse_async_t;
   30 
   31 static int gf_fuse_xattr_enotsup_log;
   32 
   33 void
   34 fini(xlator_t *this_xl);
   35 
   36 static void
   37 fuse_invalidate_inode(xlator_t *this, uint64_t fuse_ino);
   38 
   39 /*
   40  * Send an invalidate notification up to fuse to purge the file from local
   41  * page cache.
   42  */
   43 
   44 static int32_t
   45 fuse_invalidate(xlator_t *this, inode_t *inode)
   46 {
   47     fuse_private_t *priv = this->private;
   48     uint64_t nodeid;
   49 
   50     /*
   51      * NOTE: We only invalidate at the moment if fopen_keep_cache is
   52      * enabled because otherwise this is a departure from default
   53      * behavior. Specifically, the performance/write-behind xlator
   54      * causes unconditional invalidations on write requests.
   55      */
   56     if (!priv->fopen_keep_cache)
   57         return 0;
   58 
   59     nodeid = inode_to_fuse_nodeid(inode);
   60     gf_log(this->name, GF_LOG_DEBUG, "Invalidate inode id %" GF_PRI_INODE ".",
   61            nodeid);
   62     fuse_log_eh(this, "Sending invalidate inode id: %" GF_PRI_INODE " gfid: %s",
   63                 nodeid, uuid_utoa(inode->gfid));
   64     fuse_invalidate_inode(this, nodeid);
   65 
   66     return 0;
   67 }
   68 
   69 static int32_t
   70 fuse_forget_cbk(xlator_t *this, inode_t *inode)
   71 {
   72     // Nothing to free in inode ctx, hence return.
   73     return 0;
   74 }
   75 
   76 fuse_fd_ctx_t *
   77 __fuse_fd_ctx_check_n_create(xlator_t *this, fd_t *fd)
   78 {
   79     uint64_t val = 0;
   80     int32_t ret = 0;
   81     fuse_fd_ctx_t *fd_ctx = NULL;
   82 
   83     ret = __fd_ctx_get(fd, this, &val);
   84 
   85     fd_ctx = (fuse_fd_ctx_t *)(unsigned long)val;
   86 
   87     if (fd_ctx == NULL) {
   88         fd_ctx = GF_CALLOC(1, sizeof(*fd_ctx), gf_fuse_mt_fd_ctx_t);
   89         if (!fd_ctx) {
   90             goto out;
   91         }
   92         ret = __fd_ctx_set(fd, this, (uint64_t)(unsigned long)fd_ctx);
   93         if (ret < 0) {
   94             gf_log("glusterfs-fuse", GF_LOG_DEBUG, "fd-ctx-set failed");
   95             GF_FREE(fd_ctx);
   96             fd_ctx = NULL;
   97         }
   98     }
   99 out:
  100     return fd_ctx;
  101 }
  102 
  103 fuse_fd_ctx_t *
  104 fuse_fd_ctx_check_n_create(xlator_t *this, fd_t *fd)
  105 {
  106     fuse_fd_ctx_t *fd_ctx = NULL;
  107 
  108     if ((fd == NULL) || (this == NULL)) {
  109         goto out;
  110     }
  111 
  112     LOCK(&fd->lock);
  113     {
  114         fd_ctx = __fuse_fd_ctx_check_n_create(this, fd);
  115     }
  116     UNLOCK(&fd->lock);
  117 
  118 out:
  119     return fd_ctx;
  120 }
  121 
  122 static void
  123 fuse_fd_ctx_destroy(xlator_t *this, fd_t *fd)
  124 {
  125     fd_t *activefd = NULL;
  126     uint64_t val = 0;
  127     int ret = 0;
  128     fuse_fd_ctx_t *fdctx = NULL;
  129 
  130     ret = fd_ctx_del(fd, this, &val);
  131     if (!ret) {
  132         fdctx = (fuse_fd_ctx_t *)(unsigned long)val;
  133         if (fdctx) {
  134             activefd = fdctx->activefd;
  135             if (activefd) {
  136                 fd_unref(activefd);
  137             }
  138 
  139             GF_FREE(fdctx);
  140         }
  141     }
  142 }
  143 
  144 fuse_fd_ctx_t *
  145 fuse_fd_ctx_get(xlator_t *this, fd_t *fd)
  146 {
  147     fuse_fd_ctx_t *fdctx = NULL;
  148     uint64_t value = 0;
  149     int ret = 0;
  150 
  151     ret = fd_ctx_get(fd, this, &value);
  152     if (ret < 0) {
  153         goto out;
  154     }
  155 
  156     fdctx = (fuse_fd_ctx_t *)(unsigned long)value;
  157 
  158 out:
  159     return fdctx;
  160 }
  161 
  162 struct fusedump_timespec {
  163     uint32_t len;
  164     uint64_t sec;
  165     uint32_t nsec;
  166 } __attribute__((packed));
  167 
  168 struct fusedump_signature {
  169     uint32_t len;
  170     char sig[8];
  171 } __attribute__((packed));
  172 
  173 static void
  174 fusedump_gettime(struct fusedump_timespec *fts)
  175 {
  176     struct timespec ts = {
  177         0,
  178     };
  179 
  180     clock_gettime(CLOCK_REALTIME, &ts);
  181 
  182     fts->sec = ts.tv_sec;
  183     fts->nsec = ts.tv_nsec;
  184 }
  185 
  186 static void
  187 fusedump_setup_meta(struct iovec *iovs, char *dir,
  188                     uint32_t *fusedump_item_count,
  189                     struct fusedump_timespec *fts,
  190                     struct fusedump_signature *fsig)
  191 {
  192     char glustersig[8] = {'G', 'L', 'U', 'S', 'T', 'E', 'R', 0xF5};
  193 
  194     *fusedump_item_count = 3;
  195     fts->len = sizeof(*fts);
  196     fusedump_gettime(fts);
  197     fsig->len = sizeof(*fsig);
  198     memcpy(fsig->sig, glustersig, 8);
  199 
  200     iovs[0] = (struct iovec){dir, sizeof(*dir)};
  201     iovs[1] = (struct iovec){fusedump_item_count, sizeof(*fusedump_item_count)};
  202     iovs[2] = (struct iovec){fts, fts->len};
  203     iovs[3] = (struct iovec){fsig, fsig->len};
  204 }
  205 
  206 static int
  207 check_and_dump_fuse_W(fuse_private_t *priv, struct iovec *iov_out, int count,
  208                       ssize_t res, errnomask_t errnomask)
  209 {
  210     char w = 'W';
  211     struct iovec diov[4] = {
  212         {
  213             0,
  214         },
  215     };
  216     uint32_t fusedump_item_count = 3;
  217     struct fusedump_timespec fts = {
  218         0,
  219     };
  220     struct fusedump_signature fsig = {
  221         0,
  222     };
  223     struct fuse_out_header *fouh = NULL;
  224 
  225     if (res == -1) {
  226         const char *errdesc = NULL;
  227         gf_loglevel_t loglevel = GF_LOG_ERROR;
  228 
  229         /* If caller masked the errno, then it
  230          * does not indicate an error at the application
  231          * level, so we degrade the log severity to DEBUG.
  232          */
  233         if (errnomask && errno < ERRNOMASK_MAX &&
  234             GET_ERRNO_MASK(errnomask, errno))
  235             loglevel = GF_LOG_DEBUG;
  236 
  237         switch (errno) {
  238             /* The listed errnos are FUSE status indicators,
  239              * not legit values according to POSIX (see write(3p)),
  240              * so resolving them according to the standard
  241              * POSIX interpretation would be misleading.
  242              */
  243             case ENOENT:
  244                 errdesc = "ENOENT";
  245                 break;
  246             case ENOTDIR:
  247                 errdesc = "ENOTDIR";
  248                 break;
  249             case ENODEV:
  250                 errdesc = "ENODEV";
  251                 break;
  252             case EPERM:
  253                 errdesc = "EPERM";
  254                 break;
  255             case ENOMEM:
  256                 errdesc = "ENOMEM";
  257                 break;
  258             case ENOTCONN:
  259                 errdesc = "ENOTCONN";
  260                 break;
  261             case ECONNREFUSED:
  262                 errdesc = "ECONNREFUSED";
  263                 break;
  264             case EOVERFLOW:
  265                 errdesc = "EOVERFLOW";
  266                 break;
  267             case EBUSY:
  268                 errdesc = "EBUSY";
  269                 break;
  270             case ENOTEMPTY:
  271                 errdesc = "ENOTEMPTY";
  272                 break;
  273             default:
  274                 errdesc = strerror(errno);
  275         }
  276 
  277         gf_log_callingfn("glusterfs-fuse", loglevel,
  278                          "writing to fuse device failed: %s", errdesc);
  279         return errno;
  280     }
  281 
  282     fouh = iov_out[0].iov_base;
  283     if (res != fouh->len) {
  284         gf_log("glusterfs-fuse", GF_LOG_ERROR,
  285                "inconsistent write to fuse device: "
  286                "written %zd, expectd %d",
  287                res, fouh->len);
  288         return EINVAL;
  289     }
  290 
  291     if (priv->fuse_dump_fd == -1)
  292         return 0;
  293 
  294     fusedump_setup_meta(diov, &w, &fusedump_item_count, &fts, &fsig);
  295 
  296     pthread_mutex_lock(&priv->fuse_dump_mutex);
  297     res = sys_writev(priv->fuse_dump_fd, diov, sizeof(diov) / sizeof(diov[0]));
  298     if (res != -1)
  299         res = sys_writev(priv->fuse_dump_fd, iov_out, count);
  300     pthread_mutex_unlock(&priv->fuse_dump_mutex);
  301 
  302     if (res == -1)
  303         gf_log("glusterfs-fuse", GF_LOG_ERROR,
  304                "failed to dump fuse message (W): %s", strerror(errno));
  305 
  306     /*
  307      * Return value reflects check on write to /dev/fuse,
  308      * so ignore issues with dumping.
  309      */
  310 
  311     return 0;
  312 }
  313 
  314 /*
  315  * iov_out should contain a fuse_out_header at zeroth position.
  316  * The error value of this header is sent to kernel.
  317  */
  318 static int
  319 send_fuse_iov(xlator_t *this, fuse_in_header_t *finh, struct iovec *iov_out,
  320               int count)
  321 {
  322     fuse_private_t *priv = NULL;
  323     struct fuse_out_header *fouh = NULL;
  324     int res, i;
  325 
  326     if (!this || !finh || !iov_out) {
  327         gf_log("send_fuse_iov", GF_LOG_ERROR, "Invalid arguments");
  328         return EINVAL;
  329     }
  330     priv = this->private;
  331 
  332     fouh = iov_out[0].iov_base;
  333     iov_out[0].iov_len = sizeof(*fouh);
  334     fouh->len = 0;
  335     for (i = 0; i < count; i++)
  336         fouh->len += iov_out[i].iov_len;
  337     fouh->unique = finh->unique;
  338 
  339     res = sys_writev(priv->fd, iov_out, count);
  340     gf_log("glusterfs-fuse", GF_LOG_TRACE, "writev() result %d/%d %s", res,
  341            fouh->len, res == -1 ? strerror(errno) : "");
  342 
  343     return check_and_dump_fuse_W(priv, iov_out, count, res, NULL);
  344 }
  345 
  346 static int
  347 send_fuse_data(xlator_t *this, fuse_in_header_t *finh, void *data, size_t size)
  348 {
  349     struct fuse_out_header fouh = {
  350         0,
  351     };
  352     struct iovec iov_out[2];
  353     int ret = 0;
  354 
  355     fouh.error = 0;
  356     iov_out[0].iov_base = &fouh;
  357     iov_out[1].iov_base = data;
  358     iov_out[1].iov_len = size;
  359 
  360     ret = send_fuse_iov(this, finh, iov_out, 2);
  361     if (ret != 0)
  362         gf_log("glusterfs-fuse", GF_LOG_ERROR,
  363                "send_fuse_iov() "
  364                "failed: %s",
  365                strerror(ret));
  366 
  367     return ret;
  368 }
  369 
  370 #define send_fuse_obj(this, finh, obj)                                         \
  371     send_fuse_data(this, finh, obj, sizeof(*(obj)))
  372 
  373 static void
  374 fuse_invalidate_entry(xlator_t *this, uint64_t fuse_ino)
  375 {
  376 #if FUSE_KERNEL_MINOR_VERSION >= 11
  377     struct fuse_out_header *fouh = NULL;
  378     struct fuse_notify_inval_entry_out *fnieo = NULL;
  379     fuse_private_t *priv = NULL;
  380     dentry_t *dentry = NULL;
  381     dentry_t *tmp = NULL;
  382     inode_t *inode = NULL;
  383     size_t nlen = 0;
  384     fuse_invalidate_node_t *node = NULL;
  385     char gfid_str[UUID_CANONICAL_FORM_LEN + 1];
  386 
  387     priv = this->private;
  388     if (!priv->reverse_fuse_thread_started)
  389         return;
  390 
  391     inode = (inode_t *)(unsigned long)fuse_ino;
  392     if (inode == NULL)
  393         return;
  394 
  395     list_for_each_entry_safe(dentry, tmp, &inode->dentry_list, inode_list)
  396     {
  397         node = GF_CALLOC(1, sizeof(*node), gf_fuse_mt_invalidate_node_t);
  398         if (node == NULL)
  399             break;
  400 
  401         INIT_LIST_HEAD(&node->next);
  402 
  403         fouh = (struct fuse_out_header *)node->inval_buf;
  404         fnieo = (struct fuse_notify_inval_entry_out *)(fouh + 1);
  405 
  406         fouh->unique = 0;
  407         fouh->error = FUSE_NOTIFY_INVAL_ENTRY;
  408 
  409         if (ENOENT < ERRNOMASK_MAX)
  410             MASK_ERRNO(node->errnomask, ENOENT);
  411         if (ENOTDIR < ERRNOMASK_MAX)
  412             MASK_ERRNO(node->errnomask, ENOTDIR);
  413         if (EBUSY < ERRNOMASK_MAX)
  414             MASK_ERRNO(node->errnomask, EBUSY);
  415         if (ENOTEMPTY < ERRNOMASK_MAX)
  416             MASK_ERRNO(node->errnomask, ENOTEMPTY);
  417 
  418         if (dentry->name) {
  419             nlen = strlen(dentry->name);
  420             fouh->len = sizeof(*fouh) + sizeof(*fnieo) + nlen + 1;
  421             fnieo->parent = inode_to_fuse_nodeid(dentry->parent);
  422 
  423             fnieo->namelen = nlen;
  424             strcpy((node->inval_buf + sizeof(*fouh) + sizeof(*fnieo)),
  425                    dentry->name);
  426         }
  427 
  428         gf_log("glusterfs-fuse", GF_LOG_TRACE,
  429                "INVALIDATE entry: %" PRIu64 "/%s (gfid:%s)", fnieo->parent,
  430                dentry->name, uuid_utoa(inode->gfid));
  431 
  432         if (dentry->parent) {
  433             fuse_log_eh(this, "Invalidated entry %s (parent: %s) gfid:%s",
  434                         dentry->name, uuid_utoa(dentry->parent->gfid),
  435                         uuid_utoa_r(inode->gfid, gfid_str));
  436         } else {
  437             fuse_log_eh(this,
  438                         "Invalidated entry %s(nodeid: %" PRIu64 ") gfid:%s",
  439                         dentry->name, fnieo->parent, uuid_utoa(inode->gfid));
  440         }
  441 
  442         pthread_mutex_lock(&priv->invalidate_mutex);
  443         {
  444             list_add_tail(&node->next, &priv->invalidate_list);
  445             pthread_cond_signal(&priv->invalidate_cond);
  446         }
  447         pthread_mutex_unlock(&priv->invalidate_mutex);
  448     }
  449 
  450 #endif
  451     return;
  452 }
  453 
  454 /*
  455  * Send an inval inode notification to fuse. This causes an invalidation of the
  456  * entire page cache mapping on the inode.
  457  */
  458 static void
  459 fuse_invalidate_inode(xlator_t *this, uint64_t fuse_ino)
  460 {
  461 #if FUSE_KERNEL_MINOR_VERSION >= 11
  462     struct fuse_out_header *fouh = NULL;
  463     struct fuse_notify_inval_inode_out *fniio = NULL;
  464     fuse_private_t *priv = NULL;
  465     fuse_invalidate_node_t *node = NULL;
  466     inode_t *inode = NULL;
  467 
  468     priv = this->private;
  469 
  470     if (!priv->reverse_fuse_thread_started)
  471         return;
  472 
  473     inode = (inode_t *)(unsigned long)fuse_ino;
  474     if (inode == NULL)
  475         return;
  476 
  477     node = GF_CALLOC(1, sizeof(*node), gf_fuse_mt_invalidate_node_t);
  478     if (node == NULL)
  479         return;
  480 
  481     INIT_LIST_HEAD(&node->next);
  482 
  483     fouh = (struct fuse_out_header *)node->inval_buf;
  484     fniio = (struct fuse_notify_inval_inode_out *)(fouh + 1);
  485 
  486     fouh->unique = 0;
  487     fouh->error = FUSE_NOTIFY_INVAL_INODE;
  488     fouh->len = sizeof(struct fuse_out_header) +
  489                 sizeof(struct fuse_notify_inval_inode_out);
  490 
  491     /* inval the entire mapping until we learn how to be more granular */
  492     fniio->ino = fuse_ino;
  493     fniio->off = 0;
  494     fniio->len = -1;
  495 
  496     if (ENOENT < ERRNOMASK_MAX)
  497         MASK_ERRNO(node->errnomask, ENOENT);
  498 
  499     fuse_log_eh(this, "Invalidated inode %" PRIu64 " (gfid: %s)", fuse_ino,
  500                 uuid_utoa(inode->gfid));
  501     gf_log("glusterfs-fuse", GF_LOG_TRACE,
  502            "INVALIDATE inode: %" PRIu64 "(gfid:%s)", fuse_ino,
  503            uuid_utoa(inode->gfid));
  504 
  505     pthread_mutex_lock(&priv->invalidate_mutex);
  506     {
  507         list_add_tail(&node->next, &priv->invalidate_list);
  508         pthread_cond_signal(&priv->invalidate_cond);
  509     }
  510     pthread_mutex_unlock(&priv->invalidate_mutex);
  511 
  512 #else
  513     gf_log("glusterfs-fuse", GF_LOG_WARNING,
  514            "fuse_invalidate_inode not implemented on this system");
  515 #endif
  516     return;
  517 }
  518 
  519 #if FUSE_KERNEL_MINOR_VERSION >= 11
  520 /* Need this function for the signature (inode_t *, instead of uint64_t) */
  521 static int32_t
  522 fuse_inode_invalidate_fn(xlator_t *this, inode_t *inode)
  523 {
  524     fuse_invalidate_entry(this, (uint64_t)(uintptr_t)inode);
  525     return 0;
  526 }
  527 #endif
  528 
  529 static fuse_timed_message_t *
  530 fuse_timed_message_new(void)
  531 {
  532     fuse_timed_message_t *dmsg = NULL;
  533 
  534     dmsg = GF_MALLOC(sizeof(*dmsg), gf_fuse_mt_timed_message_t);
  535     if (!dmsg) {
  536         return NULL;
  537     }
  538 
  539     /* should be NULL if not set */
  540     dmsg->fuse_message_body = NULL;
  541     INIT_LIST_HEAD(&dmsg->next);
  542     memset(dmsg->errnomask, 0, sizeof(dmsg->errnomask));
  543 
  544     return dmsg;
  545 }
  546 
  547 static void
  548 fuse_timed_message_free(fuse_timed_message_t *dmsg)
  549 {
  550     GF_FREE(dmsg->fuse_message_body);
  551     GF_FREE(dmsg);
  552 }
  553 
  554 static void
  555 send_fuse_timed(xlator_t *this, fuse_timed_message_t *dmsg)
  556 {
  557     fuse_private_t *priv = NULL;
  558 
  559     priv = this->private;
  560 
  561     if (!priv->timed_response_fuse_thread_started) {
  562         return;
  563     }
  564 
  565     pthread_mutex_lock(&priv->timed_mutex);
  566     {
  567         list_add_tail(&dmsg->next, &priv->timed_list);
  568         pthread_cond_signal(&priv->timed_cond);
  569     }
  570     pthread_mutex_unlock(&priv->timed_mutex);
  571 }
  572 
  573 fuse_interrupt_record_t *
  574 fuse_interrupt_record_new(fuse_in_header_t *finh,
  575                           fuse_interrupt_handler_t handler)
  576 {
  577     fuse_interrupt_record_t *fir = NULL;
  578 
  579     fir = GF_MALLOC(sizeof(*fir), gf_fuse_mt_interrupt_record_t);
  580     if (!fir) {
  581         return NULL;
  582     }
  583 
  584     fir->hit = _gf_false;
  585     fir->interrupt_state = INTERRUPT_NONE;
  586     fir->data = NULL;
  587 
  588     fir->interrupt_handler = handler;
  589     memcpy(&fir->fuse_in_header, finh, sizeof(*finh));
  590     pthread_cond_init(&fir->handler_cond, NULL);
  591     pthread_mutex_init(&fir->handler_mutex, NULL);
  592     INIT_LIST_HEAD(&fir->next);
  593 
  594     return fir;
  595 }
  596 
  597 static void
  598 fuse_interrupt_record_free(fuse_interrupt_record_t *fir, void **datap)
  599 {
  600     /*
  601      * If caller wishes, we give back the private data to let them deal with it
  602      * however they want; otherwise we take care of freeing it.
  603      */
  604     if (datap) {
  605         *datap = fir->data;
  606     } else {
  607         GF_FREE(fir->data);
  608     }
  609 
  610     GF_FREE(fir);
  611 }
  612 
  613 void
  614 fuse_interrupt_record_insert(xlator_t *this, fuse_interrupt_record_t *fir)
  615 {
  616     fuse_private_t *priv = NULL;
  617 
  618     priv = this->private;
  619     pthread_mutex_lock(&priv->interrupt_mutex);
  620     {
  621         list_add_tail(&fir->next, &priv->interrupt_list);
  622     }
  623     pthread_mutex_unlock(&priv->interrupt_mutex);
  624 }
  625 
  626 static fuse_interrupt_record_t *
  627 fuse_interrupt_record_fetch(xlator_t *this, uint64_t unique, gf_boolean_t reap)
  628 {
  629     fuse_interrupt_record_t *fir = NULL;
  630     gf_boolean_t found = _gf_false;
  631     fuse_private_t *priv = NULL;
  632 
  633     priv = this->private;
  634     pthread_mutex_lock(&priv->interrupt_mutex);
  635     {
  636         list_for_each_entry(fir, &priv->interrupt_list, next)
  637         {
  638             if (fir->fuse_in_header.unique == unique) {
  639                 /*
  640                  * If we are to reap, we do it regardless the
  641                  * hit flag; otherwise we take the record only
  642                  * hasn't yet flagged hit.
  643                  */
  644                 if (reap || !fir->hit) {
  645                     found = _gf_true;
  646                 }
  647                 /*
  648                  * If we are not reaping (coming from handler
  649                  * context), we set the hit flag.
  650                  */
  651                 if (!reap) {
  652                     fir->hit = _gf_true;
  653                 }
  654                 break;
  655             }
  656         }
  657         if (found && reap) {
  658             list_del(&fir->next);
  659         }
  660     }
  661     pthread_mutex_unlock(&priv->interrupt_mutex);
  662 
  663     if (found) {
  664         return fir;
  665     }
  666     return NULL;
  667 }
  668 
  669 static fuse_interrupt_record_t *
  670 fuse_interrupt_record_get(xlator_t *this, uint64_t unique)
  671 {
  672     return fuse_interrupt_record_fetch(this, unique, _gf_false);
  673 }
  674 
  675 static fuse_interrupt_record_t *
  676 fuse_interrupt_record_reap(xlator_t *this, uint64_t unique)
  677 {
  678     return fuse_interrupt_record_fetch(this, unique, _gf_true);
  679 }
  680 
  681 static void
  682 fuse_interrupt(xlator_t *this, fuse_in_header_t *finh, void *msg,
  683                struct iobuf *iobuf)
  684 {
  685     struct fuse_interrupt_in *fii = msg;
  686     fuse_interrupt_record_t *fir = NULL;
  687 
  688     gf_log("glusterfs-fuse", GF_LOG_TRACE,
  689            "unique %" PRIu64 " INTERRUPT for %" PRIu64, finh->unique,
  690            fii->unique);
  691 
  692     fir = fuse_interrupt_record_get(this, fii->unique);
  693     if (fir) {
  694         gf_log("glusterfs-fuse", GF_LOG_DEBUG,
  695                "unique %" PRIu64 " INTERRUPT for %" PRIu64
  696                ": handler triggered",
  697                finh->unique, fii->unique);
  698 
  699         fir->interrupt_handler(this, fir);
  700     } else {
  701         fuse_timed_message_t *dmsg = NULL;
  702 
  703         /*
  704          * No record found for this interrupt request.
  705          *
  706          * It's either because the handler for the interrupted message
  707          * does not want to handle interrupt, or this interrupt
  708          * message beat the interrupted which hasn't yet added a record
  709          * to the interrupt queue. Either case we reply with error
  710          * EAGAIN with some (0.01 sec) delay. That will have this
  711          * interrupt request resent, unless the interrupted message
  712          * has been already answered.
  713          *
  714          * So effectively we are looping in between kernel and
  715          * userspace, which will be exited either when the interrupted
  716          * message handler has added an interrupt record, or has
  717          * replied to kernel. See
  718          *
  719          * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/
  720          * linux.git/tree/Documentation/filesystems/fuse.txt?h=v4.18#n148
  721          */
  722 
  723         gf_log("glusterfs-fuse", GF_LOG_DEBUG,
  724                "unique %" PRIu64 " INTERRUPT for %" PRIu64 ": no handler found",
  725                finh->unique, fii->unique);
  726 
  727         dmsg = fuse_timed_message_new();
  728         if (!dmsg) {
  729             gf_log("glusterfs-fuse", GF_LOG_ERROR,
  730                    "unique %" PRIu64 " INTERRUPT for %" PRIu64
  731                    ":"
  732                    " failed to allocate timed message",
  733                    finh->unique, fii->unique);
  734 
  735             goto out;
  736         }
  737 
  738         dmsg->fuse_out_header.unique = finh->unique;
  739         dmsg->fuse_out_header.len = sizeof(dmsg->fuse_out_header);
  740         dmsg->fuse_out_header.error = -EAGAIN;
  741         if (ENOENT < ERRNOMASK_MAX)
  742             MASK_ERRNO(dmsg->errnomask, ENOENT);
  743         timespec_now(&dmsg->scheduled_ts);
  744         timespec_adjust_delta(&dmsg->scheduled_ts,
  745                               (struct timespec){0, 10000000});
  746 
  747         send_fuse_timed(this, dmsg);
  748     }
  749 
  750 out:
  751     GF_FREE(finh);
  752 }
  753 
  754 /*
  755  * Function to be called in fop cbk context (if the fop engages
  756  * with interrupt handling).
  757  */
  758 gf_boolean_t
  759 fuse_interrupt_finish_fop(call_frame_t *frame, xlator_t *this,
  760                           gf_boolean_t sync, void **datap)
  761 {
  762     fuse_interrupt_record_t *fir = NULL;
  763     fuse_state_t *state = frame->root->state;
  764     fuse_in_header_t *finh = state->finh;
  765     gf_boolean_t hit = _gf_false;
  766     gf_boolean_t handled = _gf_false;
  767     fuse_interrupt_state_t intstat_orig = INTERRUPT_NONE;
  768 
  769     fir = fuse_interrupt_record_reap(this, finh->unique);
  770     if (!fir) {
  771         /*
  772          * No interrupt record was inserted (however, caller would usually know
  773          * about that and there is no point then in calling this function).
  774          */
  775         return _gf_false;
  776     }
  777 
  778     /*
  779      * The interrupt handler (if finds the record) modifies fir->hit; however,
  780      * that could have occurred only before fuse_interrupt_record_reap(), so
  781      * we are safe here with a lock-free access.
  782      */
  783     hit = fir->hit;
  784     if (hit) {
  785         pthread_mutex_lock(&fir->handler_mutex);
  786         {
  787             intstat_orig = fir->interrupt_state;
  788             if (fir->interrupt_state == INTERRUPT_NONE) {
  789                 fir->interrupt_state = INTERRUPT_SQUELCHED;
  790                 if (sync) {
  791                     while (fir->interrupt_state == INTERRUPT_NONE) {
  792                         pthread_cond_wait(&fir->handler_cond,
  793                                           &fir->handler_mutex);
  794                     }
  795                 }
  796             }
  797         }
  798         pthread_mutex_unlock(&fir->handler_mutex);
  799     }
  800 
  801     gf_log("glusterfs-fuse", GF_LOG_DEBUG, "intstat_orig=%d", intstat_orig);
  802 
  803     /*
  804      * From this on fir can only be referred under the conditions that imply
  805      * we are to free it (otherwise interrupt handler might have already freed
  806      * it).
  807      */
  808 
  809     if (/* there was no interrupt */
  810         !hit ||
  811         /* lost the race against interrupt handler */
  812         intstat_orig != INTERRUPT_NONE ||
  813         /* we took cleaning up on us */
  814         sync) {
  815         /* cleaning up */
  816         fuse_interrupt_record_free(fir, datap);
  817     } else if (datap) {
  818         *datap = NULL;
  819     }
  820 
  821     handled = (intstat_orig == INTERRUPT_HANDLED);
  822     if (handled) {
  823         /*
  824          * Fuse request was answered already from interrupt context, we can do
  825          * away with the stack.
  826          */
  827         free_fuse_state(state);
  828         STACK_DESTROY(frame->root);
  829     }
  830 
  831     /*
  832      * Let caller know if they have to answer the fuse request.
  833      */
  834     return handled;
  835 }
  836 
  837 /*
  838  * Function to be called in interrupt handler context.
  839  */
  840 void
  841 fuse_interrupt_finish_interrupt(xlator_t *this, fuse_interrupt_record_t *fir,
  842                                 fuse_interrupt_state_t intstat,
  843                                 gf_boolean_t sync, void **datap)
  844 {
  845     fuse_in_header_t finh = {
  846         0,
  847     };
  848     fuse_interrupt_state_t intstat_orig = INTERRUPT_NONE;
  849 
  850     pthread_mutex_lock(&fir->handler_mutex);
  851     {
  852         intstat_orig = fir->interrupt_state;
  853         if (fir->interrupt_state == INTERRUPT_NONE) {
  854             fir->interrupt_state = intstat;
  855             if (sync) {
  856                 pthread_cond_signal(&fir->handler_cond);
  857             }
  858         }
  859         finh = fir->fuse_in_header;
  860     }
  861     pthread_mutex_unlock(&fir->handler_mutex);
  862 
  863     gf_log("glusterfs-fuse", GF_LOG_DEBUG, "intstat_orig=%d", intstat_orig);
  864 
  865     /*
  866      * From this on fir can only be referred under the conditions that imply
  867      * we are to free it (otherwise fop handler might have already freed it).
  868      */
  869 
  870     if (/* we won the race, response is up to us */
  871         intstat_orig == INTERRUPT_NONE &&
  872         /* interrupt handling was successful, let the kernel know */
  873         intstat == INTERRUPT_HANDLED) {
  874         send_fuse_err(this, &finh, EINTR);
  875     }
  876 
  877     if (/* lost the race ... */
  878         intstat_orig != INTERRUPT_NONE &&
  879         /*
  880          * ... and there is no contract with fop handler that it does the
  881          * cleanup ...
  882          */
  883         !sync) {
  884         /* ... so we do! */
  885         fuse_interrupt_record_free(fir, datap);
  886     } else if (datap) {
  887         *datap = NULL;
  888     }
  889 }
  890 
  891 int
  892 send_fuse_err(xlator_t *this, fuse_in_header_t *finh, int error)
  893 {
  894     struct fuse_out_header fouh = {
  895         0,
  896     };
  897     struct iovec iov_out;
  898     inode_t *inode = NULL;
  899 
  900     fouh.error = -error;
  901     iov_out.iov_base = &fouh;
  902 
  903     inode = fuse_ino_to_inode(finh->nodeid, this);
  904 
  905     // filter out ENOENT
  906     if (error != ENOENT) {
  907         if (inode) {
  908             fuse_log_eh(this,
  909                         "Sending %s for operation %d on "
  910                         "inode %s",
  911                         strerror(error), finh->opcode, uuid_utoa(inode->gfid));
  912         } else {
  913             fuse_log_eh(this,
  914                         "Sending %s for operation %d on "
  915                         "inode %" GF_PRI_INODE,
  916                         strerror(error), finh->opcode, finh->nodeid);
  917         }
  918     }
  919 
  920     if (inode)
  921         inode_unref(inode);
  922 
  923     return send_fuse_iov(this, finh, &iov_out, 1);
  924 }
  925 
  926 static int
  927 fuse_entry_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
  928                int32_t op_ret, int32_t op_errno, inode_t *inode,
  929                struct iatt *buf, dict_t *xdata)
  930 {
  931     fuse_state_t *state = NULL;
  932     fuse_in_header_t *finh = NULL;
  933     struct fuse_entry_out feo = {
  934         0,
  935     };
  936     fuse_private_t *priv = NULL;
  937     inode_t *linked_inode = NULL;
  938     uint64_t ctx_value = LOOKUP_NOT_NEEDED;
  939 
  940     priv = this->private;
  941     state = frame->root->state;
  942     finh = state->finh;
  943 
  944     if (op_ret == 0) {
  945         if (__is_root_gfid(state->loc.inode->gfid))
  946             buf->ia_ino = 1;
  947         if (gf_uuid_is_null(buf->ia_gfid)) {
  948             /* With a NULL gfid inode linking is
  949                not possible. Let's not pretend this
  950                call was a "success".
  951             */
  952             gf_log("glusterfs-fuse", GF_LOG_WARNING,
  953                    "Received NULL gfid for %s. Forcing EIO", state->loc.path);
  954             op_ret = -1;
  955             op_errno = EIO;
  956         }
  957     }
  958 
  959     /* log into the event-history after the null uuid check is done, since
  960      * the op_ret and op_errno are being changed if the gfid is NULL.
  961      */
  962     fuse_log_eh(
  963         this,
  964         "op_ret: %d op_errno: %d "
  965         "%" PRIu64 ": %s() %s => %s",
  966         op_ret, op_errno, frame->root->unique, gf_fop_list[frame->root->op],
  967         state->loc.path,
  968         (op_ret == 0) ? uuid_utoa(buf->ia_gfid) : uuid_utoa(state->loc.gfid));
  969 
  970     if (op_ret == 0) {
  971         gf_log("glusterfs-fuse", GF_LOG_TRACE,
  972                "%" PRIu64 ": %s() %s => %" PRIu64, frame->root->unique,
  973                gf_fop_list[frame->root->op], state->loc.path, buf->ia_ino);
  974 
  975         buf->ia_blksize = this->ctx->page_size;
  976         gf_fuse_stat2attr(buf, &feo.attr, priv->enable_ino32);
  977 
  978         if (!buf->ia_ino) {
  979             gf_log("glusterfs-fuse", GF_LOG_WARNING,
  980                    "%" PRIu64 ": %s() %s returning inode 0",
  981                    frame->root->unique, gf_fop_list[frame->root->op],
  982                    state->loc.path);
  983         }
  984 
  985         linked_inode = inode_link(inode, state->loc.parent, state->loc.name,
  986                                   buf);
  987 
  988         if (linked_inode == inode) {
  989             inode_ctx_set(linked_inode, this, &ctx_value);
  990         }
  991 
  992         inode_lookup(linked_inode);
  993 
  994         feo.nodeid = inode_to_fuse_nodeid(linked_inode);
  995 
  996         inode_unref(linked_inode);
  997 
  998         feo.entry_valid = calc_timeout_sec(priv->entry_timeout);
  999         feo.entry_valid_nsec = calc_timeout_nsec(priv->entry_timeout);
 1000         feo.attr_valid = calc_timeout_sec(priv->attribute_timeout);
 1001         feo.attr_valid_nsec = calc_timeout_nsec(priv->attribute_timeout);
 1002 
 1003 #if FUSE_KERNEL_MINOR_VERSION >= 9
 1004         priv->proto_minor >= 9
 1005             ? send_fuse_obj(this, finh, &feo)
 1006             : send_fuse_data(this, finh, &feo, FUSE_COMPAT_ENTRY_OUT_SIZE);
 1007 #else
 1008         send_fuse_obj(this, finh, &feo);
 1009 #endif
 1010     } else {
 1011         gf_log("glusterfs-fuse",
 1012                (op_errno == ENOENT ? GF_LOG_TRACE : GF_LOG_WARNING),
 1013                "%" PRIu64 ": %s() %s => -1 (%s)", frame->root->unique,
 1014                gf_fop_list[frame->root->op], state->loc.path,
 1015                strerror(op_errno));
 1016 
 1017         if ((op_errno == ENOENT) && (priv->negative_timeout != 0)) {
 1018             feo.entry_valid = calc_timeout_sec(priv->negative_timeout);
 1019             feo.entry_valid_nsec = calc_timeout_nsec(priv->negative_timeout);
 1020             send_fuse_obj(this, finh, &feo);
 1021         } else {
 1022             send_fuse_err(this, state->finh, op_errno);
 1023         }
 1024     }
 1025 
 1026     free_fuse_state(state);
 1027     STACK_DESTROY(frame->root);
 1028     return 0;
 1029 }
 1030 
 1031 static int
 1032 fuse_newentry_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1033                   int32_t op_ret, int32_t op_errno, inode_t *inode,
 1034                   struct iatt *buf, struct iatt *preparent,
 1035                   struct iatt *postparent, dict_t *xdata)
 1036 {
 1037     /* facilitate retry of link from VFS */
 1038     if (op_errno == ENOENT)
 1039         op_errno = ESTALE;
 1040 
 1041     fuse_entry_cbk(frame, cookie, this, op_ret, op_errno, inode, buf, xdata);
 1042     return 0;
 1043 }
 1044 
 1045 static int
 1046 fuse_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1047                 int32_t op_ret, int32_t op_errno, inode_t *inode,
 1048                 struct iatt *stat, dict_t *dict, struct iatt *postparent)
 1049 {
 1050     fuse_state_t *state = NULL;
 1051     call_frame_t *prev = NULL;
 1052     inode_table_t *itable = NULL;
 1053 
 1054     state = frame->root->state;
 1055     prev = cookie;
 1056 
 1057     if (op_ret == -1 && state->is_revalidate == 1) {
 1058         itable = state->itable;
 1059         /*
 1060          * A stale mapping might exist for a dentry/inode that has been
 1061          * removed from another client.
 1062          */
 1063         if (op_errno == ENOENT)
 1064             inode_unlink(state->loc.inode, state->loc.parent, state->loc.name);
 1065         inode_unref(state->loc.inode);
 1066         state->loc.inode = inode_new(itable);
 1067         state->is_revalidate = 2;
 1068         if (gf_uuid_is_null(state->gfid))
 1069             gf_uuid_generate(state->gfid);
 1070         fuse_gfid_set(state);
 1071 
 1072         STACK_WIND(frame, fuse_lookup_cbk, prev->this, prev->this->fops->lookup,
 1073                    &state->loc, state->xdata);
 1074         return 0;
 1075     }
 1076 
 1077     fuse_entry_cbk(frame, cookie, this, op_ret, op_errno, inode, stat, dict);
 1078     return 0;
 1079 }
 1080 
 1081 void
 1082 fuse_fop_resume(fuse_state_t *state)
 1083 {
 1084     fuse_resume_fn_t fn = NULL;
 1085 
 1086     /*
 1087      * Fail fd resolution failures right away.
 1088      */
 1089     if (state->resolve.fd && state->resolve.op_ret < 0) {
 1090         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 1091         free_fuse_state(state);
 1092         return;
 1093     }
 1094 
 1095     fn = state->resume_fn;
 1096     fn(state);
 1097 }
 1098 
 1099 void
 1100 fuse_lookup_resume(fuse_state_t *state)
 1101 {
 1102     if (!state->loc.parent && !state->loc.inode) {
 1103         gf_log("fuse", GF_LOG_ERROR, "failed to resolve path %s",
 1104                state->loc.path);
 1105         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 1106         free_fuse_state(state);
 1107         return;
 1108     }
 1109 
 1110     /* parent was resolved, entry could not, may be a missing gfid?
 1111      * Hence try to do a regular lookup
 1112      */
 1113     if ((state->resolve.op_ret == -1) && (state->resolve.op_errno == ENODATA)) {
 1114         state->resolve.op_ret = 0;
 1115     }
 1116 
 1117     if (state->loc.inode) {
 1118         gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": LOOKUP %s(%s)",
 1119                state->finh->unique, state->loc.path,
 1120                uuid_utoa(state->loc.inode->gfid));
 1121         state->is_revalidate = 1;
 1122     } else {
 1123         gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": LOOKUP %s",
 1124                state->finh->unique, state->loc.path);
 1125         state->loc.inode = inode_new(state->loc.parent->table);
 1126         if (gf_uuid_is_null(state->gfid))
 1127             gf_uuid_generate(state->gfid);
 1128         fuse_gfid_set(state);
 1129     }
 1130 
 1131     FUSE_FOP(state, fuse_lookup_cbk, GF_FOP_LOOKUP, lookup, &state->loc,
 1132              state->xdata);
 1133 }
 1134 
 1135 static void
 1136 fuse_lookup(xlator_t *this, fuse_in_header_t *finh, void *msg,
 1137             struct iobuf *iobuf)
 1138 {
 1139     char *name = msg;
 1140     fuse_state_t *state = NULL;
 1141 
 1142     GET_STATE(this, finh, state);
 1143 
 1144     (void)fuse_resolve_entry_init(state, &state->resolve, finh->nodeid, name);
 1145 
 1146     fuse_resolve_and_resume(state, fuse_lookup_resume);
 1147 
 1148     return;
 1149 }
 1150 
 1151 static void
 1152 do_forget(xlator_t *this, uint64_t unique, uint64_t nodeid, uint64_t nlookup)
 1153 {
 1154     inode_t *fuse_inode = fuse_ino_to_inode(nodeid, this);
 1155 
 1156     gf_log("fuse", GF_LOG_TRACE,
 1157            "%" PRIu64 ": FORGET %" PRIu64 "/%" PRIu64 " gfid: (%s)", unique,
 1158            nodeid, nlookup, uuid_utoa(fuse_inode->gfid));
 1159 
 1160     fuse_log_eh(this, "%" PRIu64 ": FORGET %" PRIu64 "/%" PRIu64 " gfid: (%s)",
 1161                 unique, nodeid, nlookup, uuid_utoa(fuse_inode->gfid));
 1162 
 1163     inode_forget_with_unref(fuse_inode, nlookup);
 1164 }
 1165 
 1166 static void
 1167 fuse_forget(xlator_t *this, fuse_in_header_t *finh, void *msg,
 1168             struct iobuf *iobuf)
 1169 
 1170 {
 1171     struct fuse_forget_in *ffi = msg;
 1172 
 1173     if (finh->nodeid == 1) {
 1174         GF_FREE(finh);
 1175         return;
 1176     }
 1177 
 1178     do_forget(this, finh->unique, finh->nodeid, ffi->nlookup);
 1179 
 1180     GF_FREE(finh);
 1181 }
 1182 
 1183 #if FUSE_KERNEL_MINOR_VERSION >= 16
 1184 static void
 1185 fuse_batch_forget(xlator_t *this, fuse_in_header_t *finh, void *msg,
 1186                   struct iobuf *iobuf)
 1187 {
 1188     struct fuse_batch_forget_in *fbfi = msg;
 1189     struct fuse_forget_one *ffo = (struct fuse_forget_one *)(fbfi + 1);
 1190     int i;
 1191 
 1192     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 1193            "%" PRIu64 ": BATCH_FORGET %" PRIu64 "/%" PRIu32, finh->unique,
 1194            finh->nodeid, fbfi->count);
 1195 
 1196     for (i = 0; i < fbfi->count; i++) {
 1197         if (ffo[i].nodeid == 1)
 1198             continue;
 1199         do_forget(this, finh->unique, ffo[i].nodeid, ffo[i].nlookup);
 1200     }
 1201     GF_FREE(finh);
 1202 }
 1203 #endif
 1204 
 1205 static int
 1206 fuse_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1207                   int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 1208                   struct iatt *postbuf, dict_t *xdata)
 1209 {
 1210     fuse_state_t *state;
 1211     fuse_in_header_t *finh;
 1212     fuse_private_t *priv = NULL;
 1213     struct fuse_attr_out fao;
 1214 
 1215     priv = this->private;
 1216     state = frame->root->state;
 1217     finh = state->finh;
 1218 
 1219     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 1220 
 1221     if (op_ret == 0) {
 1222         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 1223                "%" PRIu64 ": %s() %s => %" PRIu64, frame->root->unique,
 1224                gf_fop_list[frame->root->op],
 1225                state->loc.path ? state->loc.path : "ERR", prebuf->ia_ino);
 1226 
 1227         postbuf->ia_blksize = this->ctx->page_size;
 1228         gf_fuse_stat2attr(postbuf, &fao.attr, priv->enable_ino32);
 1229 
 1230         fao.attr_valid = calc_timeout_sec(priv->attribute_timeout);
 1231         fao.attr_valid_nsec = calc_timeout_nsec(priv->attribute_timeout);
 1232 
 1233 #if FUSE_KERNEL_MINOR_VERSION >= 9
 1234         priv->proto_minor >= 9
 1235             ? send_fuse_obj(this, finh, &fao)
 1236             : send_fuse_data(this, finh, &fao, FUSE_COMPAT_ATTR_OUT_SIZE);
 1237 #else
 1238         send_fuse_obj(this, finh, &fao);
 1239 #endif
 1240     } else {
 1241         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 1242                "%" PRIu64 ": %s() %s => -1 (%s)", frame->root->unique,
 1243                gf_fop_list[frame->root->op],
 1244                state->loc.path ? state->loc.path : "ERR", strerror(op_errno));
 1245 
 1246         /* facilitate retry from VFS */
 1247         if ((state->fd == NULL) && (op_errno == ENOENT))
 1248             op_errno = ESTALE;
 1249 
 1250         send_fuse_err(this, finh, op_errno);
 1251     }
 1252 
 1253     free_fuse_state(state);
 1254     STACK_DESTROY(frame->root);
 1255 
 1256     return 0;
 1257 }
 1258 
 1259 static int
 1260 fuse_root_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1261                      int32_t op_ret, int32_t op_errno, inode_t *inode,
 1262                      struct iatt *stat, dict_t *dict, struct iatt *postparent);
 1263 
 1264 static int
 1265 fuse_attr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 1266               int32_t op_errno, struct iatt *buf, dict_t *xdata)
 1267 {
 1268     int32_t ret = 0;
 1269     fuse_state_t *state;
 1270     fuse_in_header_t *finh;
 1271     fuse_private_t *priv = NULL;
 1272     struct fuse_attr_out fao;
 1273 
 1274     priv = this->private;
 1275     state = frame->root->state;
 1276     finh = state->finh;
 1277 
 1278     fuse_log_eh(this,
 1279                 "op_ret: %d, op_errno: %d, %" PRIu64
 1280                 ": %s() %s => "
 1281                 "gfid: %s",
 1282                 op_ret, op_errno, frame->root->unique,
 1283                 gf_fop_list[frame->root->op], state->loc.path,
 1284                 state->loc.inode ? uuid_utoa(state->loc.inode->gfid) : "");
 1285     if (op_ret == 0) {
 1286         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 1287                "%" PRIu64 ": %s() %s => %" PRIu64, frame->root->unique,
 1288                gf_fop_list[frame->root->op],
 1289                state->loc.path ? state->loc.path : "ERR", buf->ia_ino);
 1290 
 1291         buf->ia_blksize = this->ctx->page_size;
 1292         gf_fuse_stat2attr(buf, &fao.attr, priv->enable_ino32);
 1293 
 1294         fao.attr_valid = calc_timeout_sec(priv->attribute_timeout);
 1295         fao.attr_valid_nsec = calc_timeout_nsec(priv->attribute_timeout);
 1296 
 1297 #if FUSE_KERNEL_MINOR_VERSION >= 9
 1298         priv->proto_minor >= 9
 1299             ? send_fuse_obj(this, finh, &fao)
 1300             : send_fuse_data(this, finh, &fao, FUSE_COMPAT_ATTR_OUT_SIZE);
 1301 #else
 1302         send_fuse_obj(this, finh, &fao);
 1303 #endif
 1304     } else {
 1305         /* This is moved here from fuse_getattr(). It makes sense as
 1306            in few cases, like the self-heal processes, some
 1307            translators expect a lookup() to come on root inode
 1308            (inode number 1). This will make sure we don't fail in any
 1309            case, but the positive path will get better performance,
 1310            by following common path for all the cases */
 1311         if ((finh->nodeid == 1) && (state->gfid[15] != 1)) {
 1312             /* The 'state->gfid[15]' check is added to prevent the
 1313                infinite recursions */
 1314             state->gfid[15] = 1;
 1315 
 1316             ret = fuse_loc_fill(&state->loc, state, finh->nodeid, 0, NULL);
 1317             if (ret < 0) {
 1318                 gf_log("glusterfs-fuse", GF_LOG_WARNING,
 1319                        "%" PRIu64 ": loc_fill() on / failed", finh->unique);
 1320                 send_fuse_err(this, finh, ENOENT);
 1321                 free_fuse_state(state);
 1322                 return 0;
 1323             }
 1324 
 1325             fuse_gfid_set(state);
 1326 
 1327             FUSE_FOP(state, fuse_root_lookup_cbk, GF_FOP_LOOKUP, lookup,
 1328                      &state->loc, state->xdata);
 1329 
 1330             return 0;
 1331         }
 1332 
 1333         /* facilitate retry from VFS */
 1334         if ((state->fd == NULL) && (op_errno == ENOENT))
 1335             op_errno = ESTALE;
 1336 
 1337         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 1338                "%" PRIu64
 1339                ": %s() "
 1340                "%s => -1 (%s)",
 1341                frame->root->unique, gf_fop_list[frame->root->op],
 1342                state->loc.path ? state->loc.path : "ERR", strerror(op_errno));
 1343 
 1344         send_fuse_err(this, finh, op_errno);
 1345     }
 1346 
 1347     free_fuse_state(state);
 1348     STACK_DESTROY(frame->root);
 1349 
 1350     return 0;
 1351 }
 1352 
 1353 static int
 1354 fuse_root_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1355                      int32_t op_ret, int32_t op_errno, inode_t *inode,
 1356                      struct iatt *stat, dict_t *dict, struct iatt *postparent)
 1357 {
 1358     fuse_attr_cbk(frame, cookie, this, op_ret, op_errno, stat, dict);
 1359 
 1360     return 0;
 1361 }
 1362 
 1363 void
 1364 fuse_getattr_resume(fuse_state_t *state)
 1365 {
 1366     if (!state->loc.inode && !(state->fd && state->fd->inode)) {
 1367         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 1368                "%" PRIu64 ": GETATTR %" PRIu64 " (%s) resolution failed",
 1369                state->finh->unique, state->finh->nodeid,
 1370                uuid_utoa(state->resolve.gfid));
 1371 
 1372         /* facilitate retry from VFS */
 1373         if ((state->fd == NULL) && (state->resolve.op_errno == ENOENT))
 1374             state->resolve.op_errno = ESTALE;
 1375 
 1376         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 1377         free_fuse_state(state);
 1378         return;
 1379     }
 1380 
 1381     if (state->fd == NULL && !IA_ISDIR(state->loc.inode->ia_type)) {
 1382         state->fd = fd_lookup(state->loc.inode, state->finh->pid);
 1383 
 1384         if (state->fd == NULL)
 1385             state->fd = fd_lookup(state->loc.inode, 0);
 1386     }
 1387 
 1388     if (!state->fd) {
 1389         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 1390                "%" PRIu64 ": GETATTR %" PRIu64 " (%s)", state->finh->unique,
 1391                state->finh->nodeid, state->loc.path);
 1392 
 1393         FUSE_FOP(state, fuse_attr_cbk, GF_FOP_STAT, stat, &state->loc,
 1394                  state->xdata);
 1395     } else {
 1396         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 1397                "%" PRIu64 ": FGETATTR %" PRIu64 " (%s/%p)", state->finh->unique,
 1398                state->finh->nodeid, state->loc.path, state->fd);
 1399 
 1400         FUSE_FOP(state, fuse_attr_cbk, GF_FOP_FSTAT, fstat, state->fd,
 1401                  state->xdata);
 1402     }
 1403 }
 1404 
 1405 static void
 1406 fuse_getattr(xlator_t *this, fuse_in_header_t *finh, void *msg,
 1407              struct iobuf *iobuf)
 1408 {
 1409 #if FUSE_KERNEL_MINOR_VERSION >= 9
 1410     struct fuse_getattr_in *fgi = msg;
 1411     fuse_private_t *priv = NULL;
 1412 #endif
 1413     fuse_state_t *state;
 1414     int ret = -1;
 1415 
 1416     GET_STATE(this, finh, state);
 1417 #if FUSE_KERNEL_MINOR_VERSION >= 9
 1418     priv = this->private;
 1419     if (priv->proto_minor >= 9 && fgi->getattr_flags & FUSE_GETATTR_FH)
 1420         state->fd = fd_ref((fd_t *)(uintptr_t)fgi->fh);
 1421 #endif
 1422     if (finh->nodeid == 1) {
 1423         state->gfid[15] = 1;
 1424 
 1425         ret = fuse_loc_fill(&state->loc, state, finh->nodeid, 0, NULL);
 1426         if (ret < 0) {
 1427             gf_log("glusterfs-fuse", GF_LOG_WARNING,
 1428                    "%" PRIu64 ": GETATTR on / (fuse_loc_fill() failed)",
 1429                    finh->unique);
 1430             send_fuse_err(this, finh, ESTALE);
 1431             free_fuse_state(state);
 1432             return;
 1433         }
 1434 
 1435         fuse_gfid_set(state);
 1436 
 1437         FUSE_FOP(state, fuse_root_lookup_cbk, GF_FOP_LOOKUP, lookup,
 1438                  &state->loc, state->xdata);
 1439         return;
 1440     }
 1441 
 1442     if (state->fd)
 1443         fuse_resolve_fd_init(state, &state->resolve, state->fd);
 1444     else
 1445         fuse_resolve_inode_init(state, &state->resolve, state->finh->nodeid);
 1446 
 1447     fuse_resolve_and_resume(state, fuse_getattr_resume);
 1448 }
 1449 
 1450 static int32_t
 1451 fuse_fd_inherit_directio(xlator_t *this, fd_t *fd, struct fuse_open_out *foo)
 1452 {
 1453     int32_t ret = 0;
 1454     fuse_fd_ctx_t *fdctx = NULL, *tmp_fdctx = NULL;
 1455     fd_t *tmp_fd = NULL;
 1456 
 1457     GF_VALIDATE_OR_GOTO_WITH_ERROR("glusterfs-fuse", this, out, ret, -EINVAL);
 1458     GF_VALIDATE_OR_GOTO_WITH_ERROR("glusterfs-fuse", fd, out, ret, -EINVAL);
 1459     GF_VALIDATE_OR_GOTO_WITH_ERROR("glusterfs-fuse", foo, out, ret, -EINVAL);
 1460 
 1461     fdctx = fuse_fd_ctx_get(this, fd);
 1462     if (!fdctx) {
 1463         ret = -ENOMEM;
 1464         goto out;
 1465     }
 1466 
 1467     tmp_fd = fd_lookup(fd->inode, 0);
 1468     if (tmp_fd) {
 1469         tmp_fdctx = fuse_fd_ctx_get(this, tmp_fd);
 1470         if (tmp_fdctx) {
 1471             foo->open_flags &= ~FOPEN_DIRECT_IO;
 1472             foo->open_flags |= (tmp_fdctx->open_flags & FOPEN_DIRECT_IO);
 1473         }
 1474     }
 1475 
 1476     fdctx->open_flags |= (foo->open_flags & FOPEN_DIRECT_IO);
 1477 
 1478     if (tmp_fd != NULL) {
 1479         fd_unref(tmp_fd);
 1480     }
 1481 
 1482     ret = 0;
 1483 out:
 1484     return ret;
 1485 }
 1486 
 1487 gf_boolean_t
 1488 direct_io_mode(dict_t *xdata)
 1489 {
 1490     if (xdata && dict_get(xdata, "direct-io-mode"))
 1491         return _gf_true;
 1492     return _gf_false;
 1493 }
 1494 
 1495 static int
 1496 fuse_fd_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 1497             int32_t op_errno, fd_t *fd, dict_t *xdata)
 1498 {
 1499     fuse_state_t *state = NULL;
 1500     fuse_in_header_t *finh = NULL;
 1501     fuse_private_t *priv = NULL;
 1502     int32_t ret = 0;
 1503     struct fuse_open_out foo = {
 1504         0,
 1505     };
 1506 
 1507     priv = this->private;
 1508     state = frame->root->state;
 1509     finh = state->finh;
 1510 
 1511     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 1512 
 1513     if (op_ret >= 0) {
 1514         foo.fh = (uintptr_t)fd;
 1515         foo.open_flags = 0;
 1516 
 1517         if (!IA_ISDIR(fd->inode->ia_type)) {
 1518             if (((priv->direct_io_mode == 2) &&
 1519                  ((state->flags & O_ACCMODE) != O_RDONLY)) ||
 1520                 (priv->direct_io_mode == 1) || (direct_io_mode(xdata)))
 1521                 foo.open_flags |= FOPEN_DIRECT_IO;
 1522 #ifdef GF_DARWIN_HOST_OS
 1523             /* In Linux: by default, buffer cache
 1524              * is purged upon open, setting
 1525              * FOPEN_KEEP_CACHE implies no-purge
 1526              *
 1527              * In MacFUSE: by default, buffer cache
 1528              * is left intact upon open, setting
 1529              * FOPEN_PURGE_UBC implies purge
 1530              *
 1531              * [[Interesting...]]
 1532              */
 1533             if (!priv->fopen_keep_cache)
 1534                 foo.open_flags |= FOPEN_PURGE_UBC;
 1535 #else
 1536             /*
 1537              * If fopen-keep-cache is enabled, we set the associated
 1538              * flag here such that files are not invalidated on open.
 1539              * File invalidations occur either in fuse or explicitly
 1540              * when the cache is set invalid on the inode.
 1541              */
 1542             if (priv->fopen_keep_cache)
 1543                 foo.open_flags |= FOPEN_KEEP_CACHE;
 1544 #endif
 1545         }
 1546 
 1547         gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": %s() %s => %p",
 1548                frame->root->unique, gf_fop_list[frame->root->op],
 1549                state->loc.path, fd);
 1550 
 1551         ret = fuse_fd_inherit_directio(this, fd, &foo);
 1552         if (ret < 0) {
 1553             op_errno = -ret;
 1554             gf_log("glusterfs-fuse", GF_LOG_WARNING,
 1555                    "cannot inherit direct-io values for fd "
 1556                    "(ptr:%p inode-gfid:%s) from fds already "
 1557                    "opened",
 1558                    fd, uuid_utoa(fd->inode->gfid));
 1559             goto err;
 1560         }
 1561 
 1562         if (send_fuse_obj(this, finh, &foo) == ENOENT) {
 1563             gf_log("glusterfs-fuse", GF_LOG_DEBUG, "open(%s) got EINTR",
 1564                    state->loc.path);
 1565             gf_fd_put(priv->fdtable, state->fd_no);
 1566             goto out;
 1567         }
 1568 
 1569         fd_bind(fd);
 1570     } else {
 1571     err:
 1572         /* OPEN(DIR) being an operation on inode should never fail with
 1573          * ENOENT. If gfid is not present, the appropriate error is
 1574          * ESTALE.
 1575          */
 1576         if (op_errno == ENOENT)
 1577             op_errno = ESTALE;
 1578 
 1579         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 1580                "%" PRIu64 ": %s() %s => -1 (%s)", frame->root->unique,
 1581                gf_fop_list[frame->root->op], state->loc.path,
 1582                strerror(op_errno));
 1583 
 1584         send_fuse_err(this, finh, op_errno);
 1585         gf_fd_put(priv->fdtable, state->fd_no);
 1586     }
 1587 out:
 1588     free_fuse_state(state);
 1589     STACK_DESTROY(frame->root);
 1590     return 0;
 1591 }
 1592 
 1593 static void
 1594 fuse_do_truncate(fuse_state_t *state)
 1595 {
 1596     if (state->fd) {
 1597         FUSE_FOP(state, fuse_truncate_cbk, GF_FOP_FTRUNCATE, ftruncate,
 1598                  state->fd, state->off, state->xdata);
 1599     } else {
 1600         FUSE_FOP(state, fuse_truncate_cbk, GF_FOP_TRUNCATE, truncate,
 1601                  &state->loc, state->off, state->xdata);
 1602     }
 1603 
 1604     return;
 1605 }
 1606 
 1607 static int
 1608 fuse_setattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1609                  int32_t op_ret, int32_t op_errno, struct iatt *statpre,
 1610                  struct iatt *statpost, dict_t *xdata)
 1611 {
 1612     fuse_state_t *state;
 1613     fuse_in_header_t *finh;
 1614     fuse_private_t *priv = NULL;
 1615     struct fuse_attr_out fao;
 1616 
 1617     int op_done = 0;
 1618 
 1619     priv = this->private;
 1620     state = frame->root->state;
 1621     finh = state->finh;
 1622 
 1623     fuse_log_eh(this,
 1624                 "op_ret: %d, op_errno: %d, %" PRIu64
 1625                 ", %s() %s => "
 1626                 "gfid: %s",
 1627                 op_ret, op_errno, frame->root->unique,
 1628                 gf_fop_list[frame->root->op], state->loc.path,
 1629                 state->loc.inode ? uuid_utoa(state->loc.inode->gfid) : "");
 1630 
 1631     if (op_ret == 0) {
 1632         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 1633                "%" PRIu64 ": %s() %s => %" PRIu64, frame->root->unique,
 1634                gf_fop_list[frame->root->op],
 1635                state->loc.path ? state->loc.path : "ERR", statpost->ia_ino);
 1636 
 1637         statpost->ia_blksize = this->ctx->page_size;
 1638         gf_fuse_stat2attr(statpost, &fao.attr, priv->enable_ino32);
 1639 
 1640         fao.attr_valid = calc_timeout_sec(priv->attribute_timeout);
 1641         fao.attr_valid_nsec = calc_timeout_nsec(priv->attribute_timeout);
 1642 
 1643         if (state->truncate_needed) {
 1644             fuse_do_truncate(state);
 1645         } else {
 1646 #if FUSE_KERNEL_MINOR_VERSION >= 9
 1647             priv->proto_minor >= 9
 1648                 ? send_fuse_obj(this, finh, &fao)
 1649                 : send_fuse_data(this, finh, &fao, FUSE_COMPAT_ATTR_OUT_SIZE);
 1650 #else
 1651             send_fuse_obj(this, finh, &fao);
 1652 #endif
 1653             op_done = 1;
 1654         }
 1655     } else {
 1656         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 1657                "%" PRIu64 ": %s() %s => -1 (%s)", frame->root->unique,
 1658                gf_fop_list[frame->root->op],
 1659                state->loc.path ? state->loc.path : "ERR", strerror(op_errno));
 1660 
 1661         /* facilitate retry from VFS */
 1662         if ((state->fd == NULL) && (op_errno == ENOENT))
 1663             op_errno = ESTALE;
 1664 
 1665         send_fuse_err(this, finh, op_errno);
 1666         op_done = 1;
 1667     }
 1668 
 1669     if (op_done) {
 1670         free_fuse_state(state);
 1671     }
 1672 
 1673     STACK_DESTROY(frame->root);
 1674 
 1675     return 0;
 1676 }
 1677 
 1678 static int32_t
 1679 fattr_to_gf_set_attr(int32_t valid)
 1680 {
 1681     int32_t gf_valid = 0;
 1682 
 1683     if (valid & FATTR_MODE)
 1684         gf_valid |= GF_SET_ATTR_MODE;
 1685 
 1686     if (valid & FATTR_UID)
 1687         gf_valid |= GF_SET_ATTR_UID;
 1688 
 1689     if (valid & FATTR_GID)
 1690         gf_valid |= GF_SET_ATTR_GID;
 1691 
 1692     if (valid & FATTR_ATIME)
 1693         gf_valid |= GF_SET_ATTR_ATIME;
 1694 
 1695     if (valid & FATTR_MTIME)
 1696         gf_valid |= GF_SET_ATTR_MTIME;
 1697 
 1698 #if FUSE_KERNEL_MINOR_VERSION >= 23
 1699     if (valid & FATTR_CTIME)
 1700         gf_valid |= GF_SET_ATTR_CTIME;
 1701 #endif
 1702 
 1703     if (valid & FATTR_SIZE)
 1704         gf_valid |= GF_SET_ATTR_SIZE;
 1705 
 1706     return gf_valid;
 1707 }
 1708 
 1709 #define FATTR_MASK                                                             \
 1710     (FATTR_SIZE | FATTR_UID | FATTR_GID | FATTR_ATIME | FATTR_MTIME |          \
 1711      FATTR_MODE)
 1712 
 1713 void
 1714 fuse_setattr_resume(fuse_state_t *state)
 1715 {
 1716     if (!state->fd && !state->loc.inode) {
 1717         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 1718                "%" PRIu64 ": SETATTR %" PRIu64 " (%s) resolution failed",
 1719                state->finh->unique, state->finh->nodeid,
 1720                uuid_utoa(state->resolve.gfid));
 1721 
 1722         /* facilitate retry from VFS */
 1723         if ((state->fd == NULL) && (state->resolve.op_errno == ENOENT))
 1724             state->resolve.op_errno = ESTALE;
 1725 
 1726         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 1727         free_fuse_state(state);
 1728         return;
 1729     }
 1730 
 1731     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 1732            "%" PRIu64 ": SETATTR (%" PRIu64 ")%s", state->finh->unique,
 1733            state->finh->nodeid, state->loc.path);
 1734 
 1735 #ifdef GF_TEST_FFOP
 1736     /* this is for calls like 'fchmod()' */
 1737     if (!state->fd)
 1738         state->fd = fd_lookup(state->loc.inode, state->finh->pid);
 1739 #endif /* GF_TEST_FFOP */
 1740 
 1741     if ((state->valid & (FATTR_MASK)) != FATTR_SIZE) {
 1742         if (state->fd &&
 1743             !((state->valid & FATTR_ATIME) || (state->valid & FATTR_MTIME)
 1744 #if FUSE_KERNEL_MINOR_VERSION >= 23
 1745               || (state->valid & FATTR_CTIME)
 1746 #endif
 1747                   )) {
 1748             /*
 1749                 there is no "futimes" call, so don't send
 1750                 fsetattr if ATIME or MTIME is set
 1751              */
 1752 
 1753             FUSE_FOP(state, fuse_setattr_cbk, GF_FOP_FSETATTR, fsetattr,
 1754                      state->fd, &state->attr,
 1755                      fattr_to_gf_set_attr(state->valid), state->xdata);
 1756         } else {
 1757             FUSE_FOP(state, fuse_setattr_cbk, GF_FOP_SETATTR, setattr,
 1758                      &state->loc, &state->attr,
 1759                      fattr_to_gf_set_attr(state->valid), state->xdata);
 1760         }
 1761     } else {
 1762         fuse_do_truncate(state);
 1763     }
 1764 }
 1765 
 1766 static void
 1767 fuse_setattr(xlator_t *this, fuse_in_header_t *finh, void *msg,
 1768              struct iobuf *iobuf)
 1769 {
 1770     struct fuse_setattr_in *fsi = msg;
 1771 
 1772 #if FUSE_KERNEL_MINOR_VERSION >= 9
 1773     fuse_private_t *priv = NULL;
 1774 #endif
 1775     fuse_state_t *state = NULL;
 1776 
 1777     GET_STATE(this, finh, state);
 1778 
 1779     if (fsi->valid & FATTR_FH && !(fsi->valid & (FATTR_ATIME | FATTR_MTIME))) {
 1780         /* We need no loc if kernel sent us an fd and
 1781          * we are not fiddling with times */
 1782         state->fd = FH_TO_FD(fsi->fh);
 1783         fuse_resolve_fd_init(state, &state->resolve, state->fd);
 1784     } else {
 1785         fuse_resolve_inode_init(state, &state->resolve, finh->nodeid);
 1786     }
 1787 
 1788     /*
 1789      * This is just stub code demonstrating how to retrieve
 1790      * lock_owner in setattr, according to the FUSE proto.
 1791      * We do not make use of ATM. Its purpose is supporting
 1792      * mandatory locking, but getting that right is further
 1793      * down the road. Cf.
 1794      *
 1795      * http://thread.gmane.org/gmane.comp.file-systems.fuse.devel/
 1796      * 4962/focus=4982
 1797      *
 1798      * http://git.kernel.org/?p=linux/kernel/git/torvalds/
 1799      * linux-2.6.git;a=commit;h=v2.6.23-5896-gf333211
 1800      */
 1801 #if FUSE_KERNEL_MINOR_VERSION >= 9
 1802     priv = this->private;
 1803     if (priv->proto_minor >= 9 && fsi->valid & FATTR_LOCKOWNER)
 1804         state->lk_owner = fsi->lock_owner;
 1805 #endif
 1806 
 1807     state->valid = fsi->valid;
 1808 
 1809     if ((fsi->valid & (FATTR_MASK)) != FATTR_SIZE) {
 1810         if (fsi->valid & FATTR_SIZE) {
 1811             state->off = fsi->size;
 1812             state->truncate_needed = _gf_true;
 1813         }
 1814 
 1815         state->attr.ia_size = fsi->size;
 1816         state->attr.ia_atime = fsi->atime;
 1817         state->attr.ia_mtime = fsi->mtime;
 1818 #if FUSE_KERNEL_MINOR_VERSION >= 23
 1819         state->attr.ia_ctime = fsi->ctime;
 1820 #endif
 1821         state->attr.ia_atime_nsec = fsi->atimensec;
 1822         state->attr.ia_mtime_nsec = fsi->mtimensec;
 1823 #if FUSE_KERNEL_MINOR_VERSION >= 23
 1824         state->attr.ia_ctime_nsec = fsi->ctimensec;
 1825 #endif
 1826 
 1827         state->attr.ia_prot = ia_prot_from_st_mode(fsi->mode);
 1828         state->attr.ia_uid = fsi->uid;
 1829         state->attr.ia_gid = fsi->gid;
 1830     } else {
 1831         state->off = fsi->size;
 1832     }
 1833 
 1834     fuse_resolve_and_resume(state, fuse_setattr_resume);
 1835 }
 1836 
 1837 static int
 1838 fuse_removexattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1839                      int32_t op_ret, int32_t op_errno, dict_t *xdata)
 1840 {
 1841     fuse_state_t *state = NULL;
 1842     fuse_in_header_t *finh = NULL;
 1843 
 1844     GF_ASSERT(frame);
 1845     GF_ASSERT(frame->root);
 1846 
 1847     state = frame->root->state;
 1848     finh = state->finh;
 1849 
 1850     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 1851 
 1852     if (op_ret == 0) {
 1853         gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": %s() %s => 0",
 1854                frame->root->unique, gf_fop_list[frame->root->op],
 1855                state->loc.path ? state->loc.path : "ERR");
 1856 
 1857         send_fuse_err(this, finh, 0);
 1858     } else {
 1859         gf_log("glusterfs-fuse",
 1860                (ENODATA == op_errno) ? GF_LOG_DEBUG : GF_LOG_WARNING,
 1861                "%" PRIu64 ": %s() of %s on %s => -1 (%s)", frame->root->unique,
 1862                gf_fop_list[frame->root->op], state->name ? state->name : "",
 1863                state->loc.path ? state->loc.path : "ERR", strerror(op_errno));
 1864 
 1865         /* facilitate retry from VFS */
 1866         if ((state->fd == NULL) && (op_errno == ENOENT))
 1867             op_errno = ESTALE;
 1868 
 1869         send_fuse_err(this, finh, op_errno);
 1870     }
 1871 
 1872     free_fuse_state(state);
 1873     STACK_DESTROY(frame->root);
 1874 
 1875     return 0;
 1876 }
 1877 
 1878 static int
 1879 fuse_err_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
 1880              int32_t op_errno, dict_t *xdata)
 1881 {
 1882     fuse_state_t *state = frame->root->state;
 1883     fuse_in_header_t *finh = state->finh;
 1884 
 1885     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 1886 
 1887     if (op_ret == 0) {
 1888         gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": %s() %s => 0",
 1889                frame->root->unique, gf_fop_list[frame->root->op],
 1890                state->loc.path ? state->loc.path : "ERR");
 1891 
 1892         send_fuse_err(this, finh, 0);
 1893     } else {
 1894         if (GF_IGNORE_IF_GSYNCD_SAFE_ERROR(frame, op_errno)) {
 1895             gf_log("glusterfs-fuse", GF_LOG_WARNING,
 1896                    "%" PRIu64 ": %s() %s => -1 (%s)", frame->root->unique,
 1897                    gf_fop_list[frame->root->op],
 1898                    state->loc.path ? state->loc.path : "ERR",
 1899                    strerror(op_errno));
 1900         }
 1901 
 1902         /* facilitate retry from VFS */
 1903         if ((state->fd == NULL) && (op_errno == ENOENT))
 1904             op_errno = ESTALE;
 1905 
 1906         send_fuse_err(this, finh, op_errno);
 1907     }
 1908 
 1909     free_fuse_state(state);
 1910     STACK_DESTROY(frame->root);
 1911 
 1912     return 0;
 1913 }
 1914 
 1915 static int
 1916 fuse_flush_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1917                int32_t op_ret, int32_t op_errno, dict_t *xdata)
 1918 {
 1919     fuse_private_t *priv = this->private;
 1920 
 1921     if (priv->flush_handle_interrupt) {
 1922         if (fuse_interrupt_finish_fop(frame, this, _gf_false, NULL)) {
 1923             return 0;
 1924         }
 1925     }
 1926 
 1927     return fuse_err_cbk(frame, cookie, this, op_ret, op_errno, xdata);
 1928 }
 1929 
 1930 static int
 1931 fuse_fsync_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1932                int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 1933                struct iatt *postbuf, dict_t *xdata)
 1934 {
 1935     return fuse_err_cbk(frame, cookie, this, op_ret, op_errno, xdata);
 1936 }
 1937 
 1938 static int
 1939 fuse_setxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1940                   int32_t op_ret, int32_t op_errno, dict_t *xdata)
 1941 {
 1942     if (op_ret == -1 && op_errno == ENOTSUP)
 1943         GF_LOG_OCCASIONALLY(gf_fuse_xattr_enotsup_log, "glusterfs-fuse",
 1944                             GF_LOG_CRITICAL,
 1945                             "extended attribute not supported "
 1946                             "by the backend storage");
 1947 
 1948     return fuse_err_cbk(frame, cookie, this, op_ret, op_errno, xdata);
 1949 }
 1950 
 1951 static int
 1952 fuse_unlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 1953                 int32_t op_ret, int32_t op_errno, struct iatt *preparent,
 1954                 struct iatt *postparent, dict_t *xdata)
 1955 {
 1956     fuse_state_t *state = NULL;
 1957     fuse_in_header_t *finh = NULL;
 1958 
 1959     state = frame->root->state;
 1960     finh = state->finh;
 1961 
 1962     fuse_log_eh(this,
 1963                 "op_ret: %d, op_errno: %d, %" PRIu64
 1964                 ": %s() %s => "
 1965                 "gfid: %s",
 1966                 op_ret, op_errno, frame->root->unique,
 1967                 gf_fop_list[frame->root->op], state->loc.path,
 1968                 state->loc.inode ? uuid_utoa(state->loc.inode->gfid) : "");
 1969 
 1970     if (op_ret == 0) {
 1971         inode_unlink(state->loc.inode, state->loc.parent, state->loc.name);
 1972         gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": %s() %s => 0",
 1973                frame->root->unique, gf_fop_list[frame->root->op],
 1974                state->loc.path);
 1975 
 1976         send_fuse_err(this, finh, 0);
 1977     } else {
 1978         if (GF_IGNORE_IF_GSYNCD_SAFE_ERROR(frame, op_errno)) {
 1979             gf_log("glusterfs-fuse",
 1980                    op_errno == ENOTEMPTY ? GF_LOG_DEBUG : GF_LOG_WARNING,
 1981                    "%" PRIu64 ": %s() %s => -1 (%s)", frame->root->unique,
 1982                    gf_fop_list[frame->root->op], state->loc.path,
 1983                    strerror(op_errno));
 1984         }
 1985         send_fuse_err(this, finh, op_errno);
 1986     }
 1987 
 1988     free_fuse_state(state);
 1989     STACK_DESTROY(frame->root);
 1990 
 1991     return 0;
 1992 }
 1993 
 1994 void
 1995 fuse_access_resume(fuse_state_t *state)
 1996 {
 1997     if (!state->loc.inode) {
 1998         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 1999                "%" PRIu64 ": ACCESS %" PRIu64 " (%s) resolution failed",
 2000                state->finh->unique, state->finh->nodeid,
 2001                uuid_utoa(state->resolve.gfid));
 2002 
 2003         /* facilitate retry from VFS */
 2004         if (state->resolve.op_errno == ENOENT)
 2005             state->resolve.op_errno = ESTALE;
 2006 
 2007         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2008         free_fuse_state(state);
 2009         return;
 2010     }
 2011 
 2012     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 2013            "%" PRIu64 " ACCESS %s/%" PRIu64 " mask=%d", state->finh->unique,
 2014            state->loc.path, state->finh->nodeid, state->mask);
 2015 
 2016     FUSE_FOP(state, fuse_err_cbk, GF_FOP_ACCESS, access, &state->loc,
 2017              state->mask, state->xdata);
 2018 }
 2019 
 2020 static void
 2021 fuse_access(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2022             struct iobuf *iobuf)
 2023 {
 2024     struct fuse_access_in *fai = msg;
 2025     fuse_state_t *state = NULL;
 2026 
 2027     GET_STATE(this, finh, state);
 2028 
 2029     fuse_resolve_inode_init(state, &state->resolve, finh->nodeid);
 2030 
 2031     state->mask = fai->mask;
 2032 
 2033     fuse_resolve_and_resume(state, fuse_access_resume);
 2034 
 2035     return;
 2036 }
 2037 
 2038 static int
 2039 fuse_readlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2040                   int32_t op_ret, int32_t op_errno, const char *linkname,
 2041                   struct iatt *buf, dict_t *xdata)
 2042 {
 2043     fuse_state_t *state = NULL;
 2044     fuse_in_header_t *finh = NULL;
 2045 
 2046     state = frame->root->state;
 2047     finh = state->finh;
 2048 
 2049     fuse_log_eh(this,
 2050                 "op_ret: %d, op_errno: %d %" PRIu64
 2051                 ": %s() => %s"
 2052                 " linkname: %s, gfid: %s",
 2053                 op_ret, op_errno, frame->root->unique,
 2054                 gf_fop_list[frame->root->op], state->loc.gfid, linkname,
 2055                 uuid_utoa(state->loc.gfid));
 2056 
 2057     if (op_ret > 0) {
 2058         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 2059                "%" PRIu64 ": %s => %s (size:%d)", frame->root->unique,
 2060                state->loc.path, linkname, op_ret);
 2061         send_fuse_data(this, finh, (void *)linkname, op_ret);
 2062     } else {
 2063         /* facilitate retry from VFS */
 2064         if (op_errno == ENOENT)
 2065             op_errno = ESTALE;
 2066 
 2067         gf_log("glusterfs-fuse", GF_LOG_WARNING, "%" PRIu64 ": %s => -1 (%s)",
 2068                frame->root->unique, state->loc.path, strerror(op_errno));
 2069 
 2070         send_fuse_err(this, finh, op_errno);
 2071     }
 2072 
 2073     free_fuse_state(state);
 2074     STACK_DESTROY(frame->root);
 2075 
 2076     return 0;
 2077 }
 2078 
 2079 void
 2080 fuse_readlink_resume(fuse_state_t *state)
 2081 {
 2082     if (!state->loc.inode) {
 2083         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 2084                "READLINK %" PRIu64 " (%s) resolution failed",
 2085                state->finh->unique, uuid_utoa(state->resolve.gfid));
 2086 
 2087         /* facilitate retry from VFS */
 2088         if (state->resolve.op_errno == ENOENT)
 2089             state->resolve.op_errno = ESTALE;
 2090 
 2091         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2092         free_fuse_state(state);
 2093         return;
 2094     }
 2095 
 2096     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 " READLINK %s/%s",
 2097            state->finh->unique, state->loc.path,
 2098            uuid_utoa(state->loc.inode->gfid));
 2099 
 2100     FUSE_FOP(state, fuse_readlink_cbk, GF_FOP_READLINK, readlink, &state->loc,
 2101              4096, state->xdata);
 2102 }
 2103 
 2104 static void
 2105 fuse_readlink(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2106               struct iobuf *iobuf)
 2107 {
 2108     fuse_state_t *state = NULL;
 2109 
 2110     GET_STATE(this, finh, state);
 2111 
 2112     fuse_resolve_inode_init(state, &state->resolve, finh->nodeid);
 2113 
 2114     fuse_resolve_and_resume(state, fuse_readlink_resume);
 2115 
 2116     return;
 2117 }
 2118 
 2119 void
 2120 fuse_mknod_resume(fuse_state_t *state)
 2121 {
 2122     if (!state->loc.parent) {
 2123         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 2124                "MKNOD %" PRIu64 "/%s (%s/%s) resolution failed",
 2125                state->finh->nodeid, state->resolve.bname,
 2126                uuid_utoa(state->resolve.gfid), state->resolve.bname);
 2127 
 2128         /* facilitate retry from VFS */
 2129         if (state->resolve.op_errno == ENOENT)
 2130             state->resolve.op_errno = ESTALE;
 2131 
 2132         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2133         free_fuse_state(state);
 2134         return;
 2135     }
 2136 
 2137     if (state->resolve.op_errno == ENOENT) {
 2138         state->resolve.op_ret = 0;
 2139         state->resolve.op_errno = 0;
 2140     }
 2141 
 2142     if (state->loc.inode) {
 2143         gf_log(state->this->name, GF_LOG_DEBUG, "inode already present");
 2144         inode_unref(state->loc.inode);
 2145         state->loc.inode = NULL;
 2146     }
 2147 
 2148     state->loc.inode = inode_new(state->loc.parent->table);
 2149 
 2150     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": MKNOD %s",
 2151            state->finh->unique, state->loc.path);
 2152 
 2153     FUSE_FOP(state, fuse_newentry_cbk, GF_FOP_MKNOD, mknod, &state->loc,
 2154              state->mode, state->rdev, state->umask, state->xdata);
 2155 }
 2156 
 2157 static void
 2158 fuse_mknod(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2159            struct iobuf *iobuf)
 2160 {
 2161     struct fuse_mknod_in *fmi = msg;
 2162     char *name = (char *)(fmi + 1);
 2163 
 2164     fuse_state_t *state = NULL;
 2165 #if FUSE_KERNEL_MINOR_VERSION >= 12
 2166     fuse_private_t *priv = NULL;
 2167     int32_t ret = -1;
 2168 
 2169     priv = this->private;
 2170     if (priv->proto_minor < 12)
 2171         name = (char *)msg + FUSE_COMPAT_MKNOD_IN_SIZE;
 2172 #endif
 2173 
 2174     GET_STATE(this, finh, state);
 2175 
 2176     gf_uuid_generate(state->gfid);
 2177 
 2178     fuse_resolve_entry_init(state, &state->resolve, finh->nodeid, name);
 2179 
 2180     state->mode = fmi->mode;
 2181     state->rdev = fmi->rdev;
 2182 
 2183 #if FUSE_KERNEL_MINOR_VERSION >= 12
 2184     priv = this->private;
 2185     FUSE_ENTRY_CREATE(this, priv, finh, state, fmi, "MKNOD");
 2186 #endif
 2187 
 2188     fuse_resolve_and_resume(state, fuse_mknod_resume);
 2189 
 2190     return;
 2191 }
 2192 
 2193 void
 2194 fuse_mkdir_resume(fuse_state_t *state)
 2195 {
 2196     if (!state->loc.parent) {
 2197         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 2198                "MKDIR %" PRIu64 " (%s/%s) resolution failed",
 2199                state->finh->nodeid, uuid_utoa(state->resolve.gfid),
 2200                state->resolve.bname);
 2201 
 2202         /* facilitate retry from VFS */
 2203         if (state->resolve.op_errno == ENOENT)
 2204             state->resolve.op_errno = ESTALE;
 2205 
 2206         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2207         free_fuse_state(state);
 2208         return;
 2209     }
 2210 
 2211     if (state->resolve.op_errno == ENOENT) {
 2212         state->resolve.op_ret = 0;
 2213         state->resolve.op_errno = 0;
 2214     }
 2215 
 2216     if (state->loc.inode) {
 2217         gf_log(state->this->name, GF_LOG_DEBUG, "inode already present");
 2218         inode_unref(state->loc.inode);
 2219         state->loc.inode = NULL;
 2220     }
 2221 
 2222     state->loc.inode = inode_new(state->loc.parent->table);
 2223 
 2224     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": MKDIR %s",
 2225            state->finh->unique, state->loc.path);
 2226 
 2227     FUSE_FOP(state, fuse_newentry_cbk, GF_FOP_MKDIR, mkdir, &state->loc,
 2228              state->mode, state->umask, state->xdata);
 2229 }
 2230 
 2231 static void
 2232 fuse_mkdir(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2233            struct iobuf *iobuf)
 2234 {
 2235     struct fuse_mkdir_in *fmi = msg;
 2236     char *name = (char *)(fmi + 1);
 2237 #if FUSE_KERNEL_MINOR_VERSION >= 12
 2238     fuse_private_t *priv = NULL;
 2239     int32_t ret = -1;
 2240 #endif
 2241 
 2242     fuse_state_t *state;
 2243 
 2244     GET_STATE(this, finh, state);
 2245 
 2246     gf_uuid_generate(state->gfid);
 2247 
 2248     fuse_resolve_entry_init(state, &state->resolve, finh->nodeid, name);
 2249 
 2250     state->mode = fmi->mode;
 2251 
 2252 #if FUSE_KERNEL_MINOR_VERSION >= 12
 2253     priv = this->private;
 2254     FUSE_ENTRY_CREATE(this, priv, finh, state, fmi, "MKDIR");
 2255 #endif
 2256 
 2257     fuse_resolve_and_resume(state, fuse_mkdir_resume);
 2258 
 2259     return;
 2260 }
 2261 
 2262 void
 2263 fuse_unlink_resume(fuse_state_t *state)
 2264 {
 2265     if (!state->loc.parent || !state->loc.inode) {
 2266         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 2267                "UNLINK %" PRIu64 " (%s/%s) resolution failed",
 2268                state->finh->nodeid, uuid_utoa(state->resolve.gfid),
 2269                state->resolve.bname);
 2270         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2271         free_fuse_state(state);
 2272         return;
 2273     }
 2274 
 2275     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": UNLINK %s",
 2276            state->finh->unique, state->loc.path);
 2277 
 2278     FUSE_FOP(state, fuse_unlink_cbk, GF_FOP_UNLINK, unlink, &state->loc, 0,
 2279              state->xdata);
 2280 }
 2281 
 2282 static void
 2283 fuse_unlink(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2284             struct iobuf *iobuf)
 2285 {
 2286     char *name = msg;
 2287     fuse_state_t *state = NULL;
 2288 
 2289     GET_STATE(this, finh, state);
 2290 
 2291     fuse_resolve_entry_init(state, &state->resolve, finh->nodeid, name);
 2292 
 2293     fuse_resolve_and_resume(state, fuse_unlink_resume);
 2294 
 2295     return;
 2296 }
 2297 
 2298 void
 2299 fuse_rmdir_resume(fuse_state_t *state)
 2300 {
 2301     if (!state->loc.parent || !state->loc.inode) {
 2302         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 2303                "RMDIR %" PRIu64 " (%s/%s) resolution failed",
 2304                state->finh->nodeid, uuid_utoa(state->resolve.gfid),
 2305                state->resolve.bname);
 2306         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2307         free_fuse_state(state);
 2308         return;
 2309     }
 2310 
 2311     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": RMDIR %s",
 2312            state->finh->unique, state->loc.path);
 2313 
 2314     FUSE_FOP(state, fuse_unlink_cbk, GF_FOP_RMDIR, rmdir, &state->loc, 0,
 2315              state->xdata);
 2316 }
 2317 
 2318 static void
 2319 fuse_rmdir(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2320            struct iobuf *iobuf)
 2321 {
 2322     char *name = msg;
 2323     fuse_state_t *state = NULL;
 2324 
 2325     GET_STATE(this, finh, state);
 2326 
 2327     fuse_resolve_entry_init(state, &state->resolve, finh->nodeid, name);
 2328 
 2329     fuse_resolve_and_resume(state, fuse_rmdir_resume);
 2330 
 2331     return;
 2332 }
 2333 
 2334 void
 2335 fuse_symlink_resume(fuse_state_t *state)
 2336 {
 2337     if (!state->loc.parent) {
 2338         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 2339                "SYMLINK %" PRIu64 " (%s/%s) -> %s resolution failed",
 2340                state->finh->nodeid, uuid_utoa(state->resolve.gfid),
 2341                state->resolve.bname, state->name);
 2342 
 2343         /* facilitate retry from VFS */
 2344         if (state->resolve.op_errno == ENOENT)
 2345             state->resolve.op_errno = ESTALE;
 2346 
 2347         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2348         free_fuse_state(state);
 2349         return;
 2350     }
 2351 
 2352     if (state->resolve.op_errno == ENOENT) {
 2353         state->resolve.op_ret = 0;
 2354         state->resolve.op_errno = 0;
 2355     }
 2356 
 2357     if (state->loc.inode) {
 2358         gf_log(state->this->name, GF_LOG_DEBUG, "inode already present");
 2359         inode_unref(state->loc.inode);
 2360         state->loc.inode = NULL;
 2361     }
 2362 
 2363     state->loc.inode = inode_new(state->loc.parent->table);
 2364 
 2365     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": SYMLINK %s -> %s",
 2366            state->finh->unique, state->loc.path, state->name);
 2367 
 2368     FUSE_FOP(state, fuse_newentry_cbk, GF_FOP_SYMLINK, symlink, state->name,
 2369              &state->loc, state->umask, state->xdata);
 2370 }
 2371 
 2372 static void
 2373 fuse_symlink(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2374              struct iobuf *iobuf)
 2375 {
 2376     char *name = msg;
 2377     char *linkname = name + strlen(name) + 1;
 2378     fuse_state_t *state = NULL;
 2379 
 2380     GET_STATE(this, finh, state);
 2381 
 2382     gf_uuid_generate(state->gfid);
 2383 
 2384     fuse_resolve_entry_init(state, &state->resolve, finh->nodeid, name);
 2385 
 2386     state->name = gf_strdup(linkname);
 2387 
 2388     fuse_resolve_and_resume(state, fuse_symlink_resume);
 2389 
 2390     return;
 2391 }
 2392 
 2393 int
 2394 fuse_rename_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2395                 int32_t op_ret, int32_t op_errno, struct iatt *buf,
 2396                 struct iatt *preoldparent, struct iatt *postoldparent,
 2397                 struct iatt *prenewparent, struct iatt *postnewparent,
 2398                 dict_t *xdata)
 2399 {
 2400     fuse_state_t *state = NULL;
 2401     fuse_in_header_t *finh = NULL;
 2402 
 2403     state = frame->root->state;
 2404     finh = state->finh;
 2405 
 2406     fuse_log_eh(this,
 2407                 "op_ret: %d, op_errno: %d, %" PRIu64
 2408                 ": %s() "
 2409                 "path: %s parent: %s ==> path: %s parent: %s"
 2410                 "gfid: %s",
 2411                 op_ret, op_errno, frame->root->unique,
 2412                 gf_fop_list[frame->root->op], state->loc.path,
 2413                 state->loc.parent ? uuid_utoa(state->loc.parent->gfid) : "",
 2414                 state->loc2.path,
 2415                 state->loc2.parent ? uuid_utoa(state->loc2.parent->gfid) : "",
 2416                 state->loc.inode ? uuid_utoa(state->loc.inode->gfid) : "");
 2417 
 2418     /* need to check for loc->parent to keep clang-scan happy.
 2419        It gets dereferenced below, and is checked for NULL above. */
 2420     if ((op_ret == 0) && (state->loc.parent) && (state->loc.inode)) {
 2421         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 2422                "%" PRIu64 ": %s -> %s => 0 (buf->ia_ino=%" PRIu64 ")",
 2423                frame->root->unique, state->loc.path, state->loc2.path,
 2424                buf->ia_ino);
 2425 
 2426         {
 2427             /* ugly ugly - to stay blind to situation where
 2428                rename happens on a new inode
 2429             */
 2430             buf->ia_type = state->loc.inode->ia_type;
 2431         }
 2432         buf->ia_blksize = this->ctx->page_size;
 2433 
 2434         inode_rename(state->loc.parent->table, state->loc.parent,
 2435                      state->loc.name, state->loc2.parent, state->loc2.name,
 2436                      state->loc.inode, buf);
 2437 
 2438         send_fuse_err(this, finh, 0);
 2439     } else {
 2440         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 2441                "%" PRIu64 ": %s -> %s => -1 (%s)", frame->root->unique,
 2442                state->loc.path, state->loc2.path, strerror(op_errno));
 2443         send_fuse_err(this, finh, op_errno);
 2444     }
 2445 
 2446     free_fuse_state(state);
 2447     STACK_DESTROY(frame->root);
 2448     return 0;
 2449 }
 2450 
 2451 void
 2452 fuse_rename_resume(fuse_state_t *state)
 2453 {
 2454     char loc_uuid[64] = {
 2455         0,
 2456     };
 2457     char loc2_uuid[64] = {
 2458         0,
 2459     };
 2460 
 2461     if (!state->loc.parent || !state->loc.inode) {
 2462         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 2463                "RENAME %" PRIu64 " %s/%s -> %s/%s src resolution failed",
 2464                state->finh->unique, uuid_utoa_r(state->resolve.gfid, loc_uuid),
 2465                state->resolve.bname,
 2466                uuid_utoa_r(state->resolve2.gfid, loc2_uuid),
 2467                state->resolve2.bname);
 2468 
 2469         /* facilitate retry from VFS */
 2470         if ((!state->loc.inode) && (state->resolve.op_errno == ENOENT))
 2471             state->resolve.op_errno = ESTALE;
 2472 
 2473         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2474         free_fuse_state(state);
 2475         return;
 2476     }
 2477 
 2478     if (!state->loc2.parent) {
 2479         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 2480                "RENAME %" PRIu64 " %s/%s -> %s/%s dst resolution failed",
 2481                state->finh->unique, uuid_utoa_r(state->resolve.gfid, loc_uuid),
 2482                state->resolve.bname,
 2483                uuid_utoa_r(state->resolve2.gfid, loc2_uuid),
 2484                state->resolve2.bname);
 2485 
 2486         send_fuse_err(state->this, state->finh, ESTALE);
 2487         free_fuse_state(state);
 2488         return;
 2489     }
 2490 
 2491     state->resolve.op_ret = 0;
 2492     state->resolve2.op_ret = 0;
 2493 
 2494     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 2495            "%" PRIu64 ": RENAME `%s (%s)' -> `%s (%s)'", state->finh->unique,
 2496            state->loc.path, loc_uuid, state->loc2.path, loc2_uuid);
 2497 
 2498     FUSE_FOP(state, fuse_rename_cbk, GF_FOP_RENAME, rename, &state->loc,
 2499              &state->loc2, state->xdata);
 2500 }
 2501 
 2502 static void
 2503 fuse_rename(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2504             struct iobuf *iobuf)
 2505 {
 2506     struct fuse_rename_in *fri = msg;
 2507     char *oldname = (char *)(fri + 1);
 2508     char *newname = oldname + strlen(oldname) + 1;
 2509     fuse_state_t *state = NULL;
 2510 
 2511     GET_STATE(this, finh, state);
 2512 
 2513     fuse_resolve_entry_init(state, &state->resolve, finh->nodeid, oldname);
 2514 
 2515     fuse_resolve_entry_init(state, &state->resolve2, fri->newdir, newname);
 2516 
 2517     fuse_resolve_and_resume(state, fuse_rename_resume);
 2518 
 2519     return;
 2520 }
 2521 
 2522 void
 2523 fuse_link_resume(fuse_state_t *state)
 2524 {
 2525     if (!state->loc2.inode || !state->loc.parent) {
 2526         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 2527                "fuse_loc_fill() failed %" PRIu64 ": LINK %s %s",
 2528                state->finh->unique, state->loc2.path, state->loc.path);
 2529 
 2530         /* facilitate retry from VFS */
 2531         if (!state->loc2.inode && (state->resolve.op_errno == ENOENT))
 2532             state->resolve.op_errno = ESTALE;
 2533 
 2534         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2535         free_fuse_state(state);
 2536         return;
 2537     }
 2538 
 2539     state->resolve.op_ret = 0;
 2540     state->resolve2.op_ret = 0;
 2541 
 2542     if (state->loc.inode) {
 2543         inode_unref(state->loc.inode);
 2544         state->loc.inode = NULL;
 2545     }
 2546     state->loc.inode = inode_ref(state->loc2.inode);
 2547 
 2548     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": LINK() %s -> %s",
 2549            state->finh->unique, state->loc2.path, state->loc.path);
 2550 
 2551     FUSE_FOP(state, fuse_newentry_cbk, GF_FOP_LINK, link, &state->loc2,
 2552              &state->loc, state->xdata);
 2553 }
 2554 
 2555 static void
 2556 fuse_link(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2557           struct iobuf *iobuf)
 2558 {
 2559     struct fuse_link_in *fli = msg;
 2560     char *name = (char *)(fli + 1);
 2561     fuse_state_t *state = NULL;
 2562 
 2563     GET_STATE(this, finh, state);
 2564 
 2565     fuse_resolve_inode_init(state, &state->resolve2, fli->oldnodeid);
 2566 
 2567     fuse_resolve_entry_init(state, &state->resolve, finh->nodeid, name);
 2568 
 2569     fuse_resolve_and_resume(state, fuse_link_resume);
 2570 
 2571     return;
 2572 }
 2573 
 2574 static int
 2575 fuse_create_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2576                 int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode,
 2577                 struct iatt *buf, struct iatt *preparent,
 2578                 struct iatt *postparent, dict_t *xdata)
 2579 {
 2580     fuse_state_t *state = NULL;
 2581     fuse_in_header_t *finh = NULL;
 2582     fuse_private_t *priv = NULL;
 2583     struct fuse_out_header fouh = {
 2584         0,
 2585     };
 2586     struct fuse_entry_out feo = {
 2587         0,
 2588     };
 2589     struct fuse_open_out foo = {
 2590         0,
 2591     };
 2592     struct iovec iov_out[3];
 2593     inode_t *linked_inode = NULL;
 2594     uint64_t ctx_value = LOOKUP_NOT_NEEDED;
 2595 
 2596     state = frame->root->state;
 2597     priv = this->private;
 2598     finh = state->finh;
 2599     foo.open_flags = 0;
 2600 
 2601     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 2602 
 2603     if (op_ret >= 0) {
 2604         foo.fh = (uintptr_t)fd;
 2605 
 2606         if (((priv->direct_io_mode == 2) &&
 2607              ((state->flags & O_ACCMODE) != O_RDONLY)) ||
 2608             (priv->direct_io_mode == 1) || direct_io_mode(xdata))
 2609             foo.open_flags |= FOPEN_DIRECT_IO;
 2610 
 2611         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 2612                "%" PRIu64 ": %s() %s => %p (ino=%" PRIu64 ")",
 2613                frame->root->unique, gf_fop_list[frame->root->op],
 2614                state->loc.path, fd, buf->ia_ino);
 2615 
 2616         buf->ia_blksize = this->ctx->page_size;
 2617         gf_fuse_stat2attr(buf, &feo.attr, priv->enable_ino32);
 2618 
 2619         linked_inode = inode_link(inode, state->loc.parent, state->loc.name,
 2620                                   buf);
 2621 
 2622         if (linked_inode != inode) {
 2623             /*
 2624                VERY racy code (if used anywhere else)
 2625                -- don't do this without understanding
 2626             */
 2627             inode_unref(fd->inode);
 2628             fd->inode = inode_ref(linked_inode);
 2629         } else {
 2630             inode_ctx_set(linked_inode, this, &ctx_value);
 2631         }
 2632 
 2633         inode_lookup(linked_inode);
 2634 
 2635         inode_unref(linked_inode);
 2636 
 2637         feo.nodeid = inode_to_fuse_nodeid(linked_inode);
 2638 
 2639         feo.entry_valid = calc_timeout_sec(priv->entry_timeout);
 2640         feo.entry_valid_nsec = calc_timeout_nsec(priv->entry_timeout);
 2641         feo.attr_valid = calc_timeout_sec(priv->attribute_timeout);
 2642         feo.attr_valid_nsec = calc_timeout_nsec(priv->attribute_timeout);
 2643 
 2644         fouh.error = 0;
 2645         iov_out[0].iov_base = &fouh;
 2646         iov_out[1].iov_base = &feo;
 2647 #if FUSE_KERNEL_MINOR_VERSION >= 9
 2648         iov_out[1].iov_len = priv->proto_minor >= 9
 2649                                  ? sizeof(feo)
 2650                                  : FUSE_COMPAT_ENTRY_OUT_SIZE;
 2651 #else
 2652         iov_out[1].iov_len = sizeof(feo);
 2653 #endif
 2654         iov_out[2].iov_base = &foo;
 2655         iov_out[2].iov_len = sizeof(foo);
 2656 
 2657         if (send_fuse_iov(this, finh, iov_out, 3) == ENOENT) {
 2658             gf_log("glusterfs-fuse", GF_LOG_DEBUG, "create(%s) got EINTR",
 2659                    state->loc.path);
 2660             inode_forget(inode, 1);
 2661             gf_fd_put(priv->fdtable, state->fd_no);
 2662             goto out;
 2663         }
 2664 
 2665         fd_bind(fd);
 2666     } else {
 2667         /* facilitate retry from VFS */
 2668         if (op_errno == ENOENT)
 2669             op_errno = ESTALE;
 2670 
 2671         gf_log("glusterfs-fuse", GF_LOG_WARNING, "%" PRIu64 ": %s => -1 (%s)",
 2672                finh->unique, state->loc.path, strerror(op_errno));
 2673 
 2674         send_fuse_err(this, finh, op_errno);
 2675         gf_fd_put(priv->fdtable, state->fd_no);
 2676     }
 2677 out:
 2678     free_fuse_state(state);
 2679     STACK_DESTROY(frame->root);
 2680 
 2681     return 0;
 2682 }
 2683 
 2684 void
 2685 fuse_create_resume(fuse_state_t *state)
 2686 {
 2687     fd_t *fd = NULL;
 2688     fuse_private_t *priv = NULL;
 2689     fuse_fd_ctx_t *fdctx = NULL;
 2690 
 2691     if (!state->loc.parent) {
 2692         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 2693                "%" PRIu64 " CREATE %s/%s resolution failed",
 2694                state->finh->unique, uuid_utoa(state->resolve.gfid),
 2695                state->resolve.bname);
 2696 
 2697         /* facilitate retry from VFS */
 2698         if (state->resolve.op_errno == ENOENT)
 2699             state->resolve.op_errno = ESTALE;
 2700 
 2701         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2702         free_fuse_state(state);
 2703         return;
 2704     }
 2705 
 2706     if (state->resolve.op_errno == ENOENT) {
 2707         state->resolve.op_ret = 0;
 2708         state->resolve.op_errno = 0;
 2709     }
 2710 
 2711     if (state->loc.inode) {
 2712         gf_log(state->this->name, GF_LOG_DEBUG, "inode already present");
 2713         inode_unref(state->loc.inode);
 2714     }
 2715 
 2716     state->loc.inode = inode_new(state->loc.parent->table);
 2717 
 2718     fd = fd_create(state->loc.inode, state->finh->pid);
 2719     if (fd == NULL) {
 2720         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 2721                "%" PRIu64 " CREATE cannot create a new fd",
 2722                state->finh->unique);
 2723         send_fuse_err(state->this, state->finh, ENOMEM);
 2724         free_fuse_state(state);
 2725         return;
 2726     }
 2727 
 2728     fdctx = fuse_fd_ctx_check_n_create(state->this, fd);
 2729     if (fdctx == NULL) {
 2730         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 2731                "%" PRIu64 " CREATE creation of fdctx failed",
 2732                state->finh->unique);
 2733         fd_unref(fd);
 2734         send_fuse_err(state->this, state->finh, ENOMEM);
 2735         free_fuse_state(state);
 2736         return;
 2737     }
 2738 
 2739     priv = state->this->private;
 2740 
 2741     state->fd_no = gf_fd_unused_get(priv->fdtable, fd);
 2742 
 2743     state->fd = fd_ref(fd);
 2744     fd->flags = state->flags;
 2745 
 2746     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": CREATE %s",
 2747            state->finh->unique, state->loc.path);
 2748 
 2749     FUSE_FOP(state, fuse_create_cbk, GF_FOP_CREATE, create, &state->loc,
 2750              state->flags, state->mode, state->umask, fd, state->xdata);
 2751 }
 2752 
 2753 static void
 2754 fuse_create(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2755             struct iobuf *iobuf)
 2756 {
 2757 #if FUSE_KERNEL_MINOR_VERSION >= 12
 2758     struct fuse_create_in *fci = msg;
 2759     fuse_private_t *priv = NULL;
 2760     int32_t ret = -1;
 2761 #else
 2762     struct fuse_open_in *fci = msg;
 2763 #endif
 2764     char *name = (char *)(fci + 1);
 2765 
 2766     fuse_state_t *state = NULL;
 2767 
 2768 #if FUSE_KERNEL_MINOR_VERSION >= 12
 2769     priv = this->private;
 2770     if (priv->proto_minor < 12)
 2771         name = (char *)((struct fuse_open_in *)msg + 1);
 2772 #endif
 2773 
 2774     GET_STATE(this, finh, state);
 2775 
 2776     gf_uuid_generate(state->gfid);
 2777 
 2778     fuse_resolve_entry_init(state, &state->resolve, finh->nodeid, name);
 2779 
 2780     state->mode = fci->mode;
 2781     state->flags = fci->flags;
 2782 
 2783 #if FUSE_KERNEL_MINOR_VERSION >= 12
 2784     priv = this->private;
 2785     FUSE_ENTRY_CREATE(this, priv, finh, state, fci, "CREATE");
 2786 #endif
 2787     fuse_resolve_and_resume(state, fuse_create_resume);
 2788 
 2789     return;
 2790 }
 2791 
 2792 void
 2793 fuse_open_resume(fuse_state_t *state)
 2794 {
 2795     fd_t *fd = NULL;
 2796     fuse_private_t *priv = NULL;
 2797     fuse_fd_ctx_t *fdctx = NULL;
 2798 
 2799     if (!state->loc.inode) {
 2800         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 2801                "%" PRIu64 ": OPEN %s resolution failed", state->finh->unique,
 2802                uuid_utoa(state->resolve.gfid));
 2803 
 2804         /* facilitate retry from VFS */
 2805         if (state->resolve.op_errno == ENOENT)
 2806             state->resolve.op_errno = ESTALE;
 2807 
 2808         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 2809         free_fuse_state(state);
 2810         return;
 2811     }
 2812 
 2813     fd = fd_create(state->loc.inode, state->finh->pid);
 2814     if (!fd) {
 2815         gf_log("fuse", GF_LOG_ERROR, "fd is NULL");
 2816         send_fuse_err(state->this, state->finh, ENOENT);
 2817         free_fuse_state(state);
 2818         return;
 2819     }
 2820 
 2821     fdctx = fuse_fd_ctx_check_n_create(state->this, fd);
 2822     if (fdctx == NULL) {
 2823         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 2824                "%" PRIu64 ": OPEN creation of fdctx failed",
 2825                state->finh->unique);
 2826         fd_unref(fd);
 2827         send_fuse_err(state->this, state->finh, ENOMEM);
 2828         free_fuse_state(state);
 2829         return;
 2830     }
 2831 
 2832     priv = state->this->private;
 2833 
 2834     state->fd_no = gf_fd_unused_get(priv->fdtable, fd);
 2835     state->fd = fd_ref(fd);
 2836     fd->flags = state->flags;
 2837 
 2838     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": OPEN %s",
 2839            state->finh->unique, state->loc.path);
 2840 
 2841     FUSE_FOP(state, fuse_fd_cbk, GF_FOP_OPEN, open, &state->loc, state->flags,
 2842              fd, state->xdata);
 2843 }
 2844 
 2845 static void
 2846 fuse_open(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2847           struct iobuf *iobuf)
 2848 {
 2849     struct fuse_open_in *foi = msg;
 2850     fuse_state_t *state = NULL;
 2851 
 2852     GET_STATE(this, finh, state);
 2853 
 2854     fuse_resolve_inode_init(state, &state->resolve, finh->nodeid);
 2855 
 2856     state->flags = foi->flags;
 2857 
 2858     fuse_resolve_and_resume(state, fuse_open_resume);
 2859 
 2860     return;
 2861 }
 2862 
 2863 static int
 2864 fuse_readv_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2865                int32_t op_ret, int32_t op_errno, struct iovec *vector,
 2866                int32_t count, struct iatt *stbuf, struct iobref *iobref,
 2867                dict_t *xdata)
 2868 {
 2869     fuse_state_t *state = NULL;
 2870     fuse_in_header_t *finh = NULL;
 2871     struct fuse_out_header fouh = {
 2872         0,
 2873     };
 2874     struct iovec *iov_out = NULL;
 2875 
 2876     state = frame->root->state;
 2877     finh = state->finh;
 2878 
 2879     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 2880 
 2881     if (op_ret >= 0) {
 2882         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 2883                "%" PRIu64 ": READ => %d/%" GF_PRI_SIZET ",%" PRId64 "/%" PRIu64,
 2884                frame->root->unique, op_ret, state->size, state->off,
 2885                stbuf->ia_size);
 2886 
 2887         iov_out = GF_CALLOC(count + 1, sizeof(*iov_out), gf_fuse_mt_iovec);
 2888         if (iov_out) {
 2889             fouh.error = 0;
 2890             iov_out[0].iov_base = &fouh;
 2891             memcpy(iov_out + 1, vector, count * sizeof(*iov_out));
 2892             send_fuse_iov(this, finh, iov_out, count + 1);
 2893             GF_FREE(iov_out);
 2894         } else
 2895             send_fuse_err(this, finh, ENOMEM);
 2896     } else {
 2897         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 2898                "%" PRIu64 ": READ => %d gfid=%s fd=%p (%s)",
 2899                frame->root->unique, op_ret,
 2900                (state->fd && state->fd->inode)
 2901                    ? uuid_utoa(state->fd->inode->gfid)
 2902                    : "nil",
 2903                state->fd, strerror(op_errno));
 2904 
 2905         send_fuse_err(this, finh, op_errno);
 2906     }
 2907 
 2908     free_fuse_state(state);
 2909     STACK_DESTROY(frame->root);
 2910 
 2911     return 0;
 2912 }
 2913 
 2914 void
 2915 fuse_readv_resume(fuse_state_t *state)
 2916 {
 2917     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 2918            "%" PRIu64 ": READ (%p, size=%zu, offset=%" PRIu64 ")",
 2919            state->finh->unique, state->fd, state->size, state->off);
 2920 
 2921     FUSE_FOP(state, fuse_readv_cbk, GF_FOP_READ, readv, state->fd, state->size,
 2922              state->off, state->io_flags, state->xdata);
 2923 }
 2924 
 2925 static void
 2926 fuse_readv(xlator_t *this, fuse_in_header_t *finh, void *msg,
 2927            struct iobuf *iobuf)
 2928 {
 2929     struct fuse_read_in *fri = msg;
 2930 
 2931 #if FUSE_KERNEL_MINOR_VERSION >= 9
 2932     fuse_private_t *priv = NULL;
 2933 #endif
 2934     fuse_state_t *state = NULL;
 2935     fd_t *fd = NULL;
 2936 
 2937     GET_STATE(this, finh, state);
 2938 
 2939     fd = FH_TO_FD(fri->fh);
 2940     state->fd = fd;
 2941 
 2942     fuse_resolve_fd_init(state, &state->resolve, fd);
 2943 
 2944     /* See comment by similar code in fuse_settatr */
 2945 #if FUSE_KERNEL_MINOR_VERSION >= 9
 2946     priv = this->private;
 2947     if (priv->proto_minor >= 9 && fri->read_flags & FUSE_READ_LOCKOWNER)
 2948         state->lk_owner = fri->lock_owner;
 2949 #endif
 2950 
 2951     state->size = fri->size;
 2952     state->off = fri->offset;
 2953     /* lets ignore 'fri->read_flags', but just consider 'fri->flags' */
 2954 #if FUSE_KERNEL_MINOR_VERSION >= 9
 2955     state->io_flags = fri->flags;
 2956 #endif
 2957     fuse_resolve_and_resume(state, fuse_readv_resume);
 2958 }
 2959 
 2960 static int
 2961 fuse_writev_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 2962                 int32_t op_ret, int32_t op_errno, struct iatt *stbuf,
 2963                 struct iatt *postbuf, dict_t *xdata)
 2964 {
 2965     fuse_state_t *state = NULL;
 2966     fuse_in_header_t *finh = NULL;
 2967     struct fuse_write_out fwo = {
 2968         0,
 2969     };
 2970 
 2971     state = frame->root->state;
 2972     finh = state->finh;
 2973 
 2974     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 2975 
 2976     if (op_ret >= 0) {
 2977         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 2978                "%" PRIu64 ": WRITE => %d/%" GF_PRI_SIZET ",%" PRId64
 2979                "/%" PRIu64,
 2980                frame->root->unique, op_ret, state->size, state->off,
 2981                stbuf->ia_size);
 2982 
 2983         fwo.size = op_ret;
 2984         send_fuse_obj(this, finh, &fwo);
 2985     } else {
 2986         gf_log(
 2987             "glusterfs-fuse", GF_LOG_WARNING,
 2988             "%" PRIu64 ": WRITE => -1 gfid=%s fd=%p (%s)", frame->root->unique,
 2989             (state->fd && state->fd->inode) ? uuid_utoa(state->fd->inode->gfid)
 2990                                             : "nil",
 2991             state->fd, strerror(op_errno));
 2992 
 2993         send_fuse_err(this, finh, op_errno);
 2994     }
 2995 
 2996     free_fuse_state(state);
 2997     STACK_DESTROY(frame->root);
 2998 
 2999     return 0;
 3000 }
 3001 
 3002 void
 3003 fuse_write_resume(fuse_state_t *state)
 3004 {
 3005     struct iobref *iobref = NULL;
 3006 
 3007     iobref = iobref_new();
 3008     if (!iobref) {
 3009         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 3010                "%" PRIu64 ": WRITE iobref allocation failed",
 3011                state->finh->unique);
 3012         send_fuse_err(state->this, state->finh, ENOMEM);
 3013 
 3014         free_fuse_state(state);
 3015         return;
 3016     }
 3017 
 3018     iobref_add(iobref, state->iobuf);
 3019 
 3020     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 3021            "%" PRIu64 ": WRITE (%p, size=%" GF_PRI_SIZET ", offset=%" PRId64
 3022            ")",
 3023            state->finh->unique, state->fd, state->size, state->off);
 3024 
 3025     FUSE_FOP(state, fuse_writev_cbk, GF_FOP_WRITE, writev, state->fd,
 3026              &state->vector, 1, state->off, state->io_flags, iobref,
 3027              state->xdata);
 3028 
 3029     iobref_unref(iobref);
 3030 }
 3031 
 3032 static void
 3033 fuse_write(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3034            struct iobuf *iobuf)
 3035 {
 3036     /* WRITE is special, metadata is attached to in_header,
 3037      * and msg is the payload as-is.
 3038      */
 3039     struct fuse_write_in *fwi = (struct fuse_write_in *)(finh + 1);
 3040 
 3041     fuse_state_t *state = NULL;
 3042     fd_t *fd = NULL;
 3043 #if FUSE_KERNEL_MINOR_VERSION >= 9
 3044     fuse_private_t *priv = NULL;
 3045     priv = this->private;
 3046 #endif
 3047 
 3048     GET_STATE(this, finh, state);
 3049     fd = FH_TO_FD(fwi->fh);
 3050     state->fd = fd;
 3051     state->size = fwi->size;
 3052     state->off = fwi->offset;
 3053 
 3054     /* lets ignore 'fwi->write_flags', but just consider 'fwi->flags' */
 3055 #if FUSE_KERNEL_MINOR_VERSION >= 9
 3056     state->io_flags = fwi->flags;
 3057 #else
 3058     state->io_flags = fwi->write_flags;
 3059 #endif
 3060     /* TODO: may need to handle below flag
 3061        (fwi->write_flags & FUSE_WRITE_CACHE);
 3062     */
 3063 
 3064     fuse_resolve_fd_init(state, &state->resolve, fd);
 3065 
 3066     /* See comment by similar code in fuse_settatr */
 3067 #if FUSE_KERNEL_MINOR_VERSION >= 9
 3068     priv = this->private;
 3069     if (priv->proto_minor >= 9 && fwi->write_flags & FUSE_WRITE_LOCKOWNER)
 3070         state->lk_owner = fwi->lock_owner;
 3071 #endif
 3072 
 3073     state->vector.iov_base = msg;
 3074     state->vector.iov_len = fwi->size;
 3075     state->iobuf = iobuf;
 3076 
 3077     fuse_resolve_and_resume(state, fuse_write_resume);
 3078 
 3079     return;
 3080 }
 3081 
 3082 #if FUSE_KERNEL_MINOR_VERSION >= 28
 3083 static int
 3084 fuse_copy_file_range_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3085                          int32_t op_ret, int32_t op_errno, struct iatt *stbuf,
 3086                          struct iatt *prebuf_dst, struct iatt *postbuf_dst,
 3087                          dict_t *xdata)
 3088 {
 3089     fuse_state_t *state = NULL;
 3090     fuse_in_header_t *finh = NULL;
 3091     /*
 3092      * Fuse kernel module uses fuse_write_out itself as the
 3093      * output collector. In fact, fuse_kernel.h in the upstream
 3094      * kernel just defines the input structure fuse_copy_file_range_in
 3095      * for the fop. So, just use the fuse_write_out to send the
 3096      * response back to the kernel.
 3097      */
 3098     struct fuse_write_out fcfro = {
 3099         0,
 3100     };
 3101 
 3102     char src_gfid[GF_UUID_BUF_SIZE] = {0};
 3103     char dst_gfid[GF_UUID_BUF_SIZE] = {0};
 3104 
 3105     state = frame->root->state;
 3106     finh = state->finh;
 3107 
 3108     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 3109 
 3110     if (op_ret >= 0) {
 3111         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 3112                "%" PRIu64 ": WRITE => %d/%" GF_PRI_SIZET ",%" PRIu64
 3113                " , %" PRIu64 " ,%" PRIu64 ",%" PRIu64,
 3114                frame->root->unique, op_ret, state->size, state->off_in,
 3115                state->off_out, stbuf->ia_size, postbuf_dst->ia_size);
 3116 
 3117         fcfro.size = op_ret;
 3118         send_fuse_obj(this, finh, &fcfro);
 3119     } else {
 3120         if (state->fd && state->fd->inode)
 3121             uuid_utoa_r(state->fd->inode->gfid, src_gfid);
 3122         else
 3123             snprintf(src_gfid, sizeof(src_gfid), "nil");
 3124 
 3125         if (state->fd_dst && state->fd_dst->inode)
 3126             uuid_utoa_r(state->fd_dst->inode->gfid, dst_gfid);
 3127         else
 3128             snprintf(dst_gfid, sizeof(dst_gfid), "nil");
 3129 
 3130         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 3131                "%" PRIu64
 3132                ": COPY_FILE_RANGE => -1 gfid_in=%s fd_in=%p "
 3133                "gfid_out=%s fd_out=%p (%s)",
 3134                frame->root->unique, src_gfid, state->fd, dst_gfid,
 3135                state->fd_dst, strerror(op_errno));
 3136 
 3137         send_fuse_err(this, finh, op_errno);
 3138     }
 3139 
 3140     free_fuse_state(state);
 3141     STACK_DESTROY(frame->root);
 3142 
 3143     return 0;
 3144 }
 3145 
 3146 void
 3147 fuse_copy_file_range_resume(fuse_state_t *state)
 3148 {
 3149     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 3150            "%" PRIu64
 3151            ": COPY_FILE_RANGE "
 3152            "(input fd: %p (gfid: %s), "
 3153            "output fd: %p (gfid: %s) size=%zu, "
 3154            "offset_in=%" PRIu64 ", offset_out=%" PRIu64 ")",
 3155            state->finh->unique, state->fd, uuid_utoa(state->fd->inode->gfid),
 3156            state->fd_dst, uuid_utoa(state->fd_dst->inode->gfid), state->size,
 3157            state->off_in, state->off_out);
 3158 
 3159     FUSE_FOP(state, fuse_copy_file_range_cbk, GF_FOP_COPY_FILE_RANGE,
 3160              copy_file_range, state->fd, state->off_in, state->fd_dst,
 3161              state->off_out, state->size, state->io_flags, state->xdata);
 3162 }
 3163 
 3164 static void
 3165 fuse_copy_file_range(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3166                      struct iobuf *iobuf)
 3167 {
 3168     struct fuse_copy_file_range_in *fcfri = msg;
 3169     fuse_state_t *state = NULL;
 3170     fd_t *fd_in = NULL;
 3171     fd_t *fd_out = NULL;
 3172 
 3173     GET_STATE(this, finh, state);
 3174 
 3175     fd_in = FH_TO_FD(fcfri->fh_in);
 3176     fd_out = FH_TO_FD(fcfri->fh_out);
 3177     state->fd = fd_in;
 3178     state->fd_dst = fd_out;
 3179 
 3180     fuse_resolve_fd_init(state, &state->resolve, fd_in);
 3181     fuse_resolve_fd_init(state, &state->resolve2, fd_out);
 3182 
 3183     state->size = fcfri->len;
 3184     state->off_in = fcfri->off_in;
 3185     state->off_out = fcfri->off_out;
 3186     state->io_flags = fcfri->flags;
 3187 
 3188     fuse_resolve_and_resume(state, fuse_copy_file_range_resume);
 3189 }
 3190 #endif /* FUSE_KERNEL_MINOR_VERSION >= 28 */
 3191 
 3192 #if FUSE_KERNEL_MINOR_VERSION >= 24 && HAVE_SEEK_HOLE
 3193 static int
 3194 fuse_lseek_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3195                int32_t op_ret, int32_t op_errno, off_t offset, dict_t *xdata)
 3196 {
 3197     fuse_state_t *state = frame->root->state;
 3198     fuse_in_header_t *finh = state->finh;
 3199     struct fuse_lseek_out flo = {
 3200         0,
 3201     };
 3202 
 3203     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 3204 
 3205     if (op_ret >= 0) {
 3206         flo.offset = offset;
 3207         send_fuse_obj(this, finh, &flo);
 3208     } else {
 3209         send_fuse_err(this, finh, op_errno);
 3210     }
 3211 
 3212     free_fuse_state(state);
 3213     STACK_DESTROY(frame->root);
 3214 
 3215     return 0;
 3216 }
 3217 
 3218 static void
 3219 fuse_lseek_resume(fuse_state_t *state)
 3220 {
 3221     FUSE_FOP(state, fuse_lseek_cbk, GF_FOP_SEEK, seek, state->fd, state->off,
 3222              state->whence, state->xdata);
 3223 }
 3224 
 3225 static void
 3226 fuse_lseek(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3227            struct iobuf *iobuf)
 3228 {
 3229     struct fuse_lseek_in *ffi = msg;
 3230     fuse_state_t *state = NULL;
 3231 
 3232     GET_STATE(this, finh, state);
 3233     state->fd = FH_TO_FD(ffi->fh);
 3234     state->off = ffi->offset;
 3235 
 3236     switch (ffi->whence) {
 3237         case SEEK_DATA:
 3238             state->whence = GF_SEEK_DATA;
 3239             break;
 3240         case SEEK_HOLE:
 3241             state->whence = GF_SEEK_HOLE;
 3242             break;
 3243         default:
 3244             /* fuse should handle other whence internally */
 3245             send_fuse_err(this, finh, EINVAL);
 3246             free_fuse_state(state);
 3247             return;
 3248     }
 3249 
 3250     fuse_resolve_fd_init(state, &state->resolve, state->fd);
 3251     fuse_resolve_and_resume(state, fuse_lseek_resume);
 3252 }
 3253 #endif /* FUSE_KERNEL_MINOR_VERSION >= 24 && HAVE_SEEK_HOLE */
 3254 
 3255 void
 3256 fuse_flush_resume(fuse_state_t *state)
 3257 {
 3258     FUSE_FOP(state, fuse_flush_cbk, GF_FOP_FLUSH, flush, state->fd,
 3259              state->xdata);
 3260 }
 3261 
 3262 static void
 3263 fuse_flush_interrupt_handler(xlator_t *this, fuse_interrupt_record_t *fir)
 3264 {
 3265     gf_log("glusterfs-fuse", GF_LOG_DEBUG,
 3266            "FLUSH unique %" PRIu64 ": interrupt handler triggered",
 3267            fir->fuse_in_header.unique);
 3268 
 3269     fuse_interrupt_finish_interrupt(this, fir, INTERRUPT_HANDLED, _gf_false,
 3270                                     NULL);
 3271 }
 3272 
 3273 static void
 3274 fuse_flush(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3275            struct iobuf *iobuf)
 3276 {
 3277     struct fuse_flush_in *ffi = msg;
 3278     fuse_private_t *priv = NULL;
 3279 
 3280     fuse_state_t *state = NULL;
 3281     fd_t *fd = NULL;
 3282 
 3283     GET_STATE(this, finh, state);
 3284     fd = FH_TO_FD(ffi->fh);
 3285     state->fd = fd;
 3286 
 3287     priv = this->private;
 3288     if (priv->flush_handle_interrupt) {
 3289         fuse_interrupt_record_t *fir = NULL;
 3290 
 3291         fir = fuse_interrupt_record_new(finh, fuse_flush_interrupt_handler);
 3292         if (!fir) {
 3293             send_fuse_err(this, finh, ENOMEM);
 3294 
 3295             gf_log("glusterfs-fuse", GF_LOG_ERROR,
 3296                    "FLUSH unique %" PRIu64
 3297                    ":"
 3298                    " interrupt record allocation failed",
 3299                    finh->unique);
 3300             free_fuse_state(state);
 3301 
 3302             return;
 3303         }
 3304         fuse_interrupt_record_insert(this, fir);
 3305     }
 3306 
 3307     fuse_resolve_fd_init(state, &state->resolve, fd);
 3308 
 3309     state->lk_owner = ffi->lock_owner;
 3310 
 3311     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": FLUSH %p",
 3312            finh->unique, fd);
 3313 
 3314     fuse_resolve_and_resume(state, fuse_flush_resume);
 3315 
 3316     return;
 3317 }
 3318 
 3319 int
 3320 fuse_internal_release(xlator_t *this, fd_t *fd)
 3321 {
 3322     /* This is important we cleanup our context here to avoid a leak
 3323        in case an error occurs and we get cleanup up by
 3324        call_unwind_error->...->args_wipe instead of the normal path.
 3325     */
 3326     fuse_fd_ctx_destroy(this, fd);
 3327 
 3328     return 0;
 3329 }
 3330 
 3331 static void
 3332 fuse_release(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3333              struct iobuf *iobuf)
 3334 {
 3335     struct fuse_release_in *fri = msg;
 3336     fd_t *fd = NULL;
 3337     fuse_state_t *state = NULL;
 3338     fuse_private_t *priv = NULL;
 3339 
 3340     GET_STATE(this, finh, state);
 3341     fd = FH_TO_FD(fri->fh);
 3342     if (!fd)
 3343         goto out;
 3344 
 3345     state->fd = fd;
 3346 
 3347     priv = this->private;
 3348 
 3349     fuse_log_eh(this, "RELEASE(): finh->unique: %" PRIu64 ":, fd: %p, gfid: %s",
 3350                 finh->unique, fd, uuid_utoa(fd->inode->gfid));
 3351 
 3352     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 3353            "finh->unique: %" PRIu64 ": RELEASE %p", finh->unique, state->fd);
 3354 
 3355     fuse_fd_ctx_destroy(this, state->fd);
 3356     fd_unref(fd);
 3357 
 3358     gf_fdptr_put(priv->fdtable, fd);
 3359 
 3360     state->fd = NULL;
 3361 
 3362 out:
 3363     send_fuse_err(this, finh, 0);
 3364 
 3365     free_fuse_state(state);
 3366     return;
 3367 }
 3368 
 3369 void
 3370 fuse_fsync_resume(fuse_state_t *state)
 3371 {
 3372     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": FSYNC %p",
 3373            state->finh->unique, state->fd);
 3374 
 3375     /* fsync_flags: 1 means "datasync" (no defines for this) */
 3376     FUSE_FOP(state, fuse_fsync_cbk, GF_FOP_FSYNC, fsync, state->fd,
 3377              (state->flags & 1), state->xdata);
 3378 }
 3379 
 3380 static void
 3381 fuse_fsync(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3382            struct iobuf *iobuf)
 3383 {
 3384     struct fuse_fsync_in *fsi = msg;
 3385 
 3386     fuse_state_t *state = NULL;
 3387     fd_t *fd = NULL;
 3388 
 3389     GET_STATE(this, finh, state);
 3390     fd = FH_TO_FD(fsi->fh);
 3391     state->fd = fd;
 3392 
 3393     fuse_resolve_fd_init(state, &state->resolve, fd);
 3394 
 3395     state->flags = fsi->fsync_flags;
 3396     fuse_resolve_and_resume(state, fuse_fsync_resume);
 3397     return;
 3398 }
 3399 
 3400 void
 3401 fuse_opendir_resume(fuse_state_t *state)
 3402 {
 3403     fd_t *fd = NULL;
 3404     fuse_private_t *priv = NULL;
 3405     fuse_fd_ctx_t *fdctx = NULL;
 3406 
 3407     priv = state->this->private;
 3408 
 3409     if (!state->loc.inode) {
 3410         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 3411                "%" PRIu64 ": OPENDIR (%s) resolution failed",
 3412                state->finh->unique, uuid_utoa(state->resolve.gfid));
 3413 
 3414         /* facilitate retry from VFS */
 3415         if (state->resolve.op_errno == ENOENT)
 3416             state->resolve.op_errno = ESTALE;
 3417 
 3418         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 3419         free_fuse_state(state);
 3420         return;
 3421     }
 3422 
 3423     fd = fd_create(state->loc.inode, state->finh->pid);
 3424     if (fd == NULL) {
 3425         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 3426                "%" PRIu64 ": OPENDIR fd creation failed", state->finh->unique);
 3427         send_fuse_err(state->this, state->finh, ENOMEM);
 3428         free_fuse_state(state);
 3429         return;
 3430     }
 3431 
 3432     fdctx = fuse_fd_ctx_check_n_create(state->this, fd);
 3433     if (fdctx == NULL) {
 3434         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 3435                "%" PRIu64 ": OPENDIR creation of fdctx failed",
 3436                state->finh->unique);
 3437         fd_unref(fd);
 3438         send_fuse_err(state->this, state->finh, ENOMEM);
 3439         free_fuse_state(state);
 3440         return;
 3441     }
 3442 
 3443     state->fd = fd_ref(fd);
 3444     state->fd_no = gf_fd_unused_get(priv->fdtable, fd);
 3445 
 3446     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": OPENDIR %s",
 3447            state->finh->unique, state->loc.path);
 3448 
 3449     FUSE_FOP(state, fuse_fd_cbk, GF_FOP_OPENDIR, opendir, &state->loc, fd,
 3450              state->xdata);
 3451 }
 3452 
 3453 static void
 3454 fuse_opendir(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3455              struct iobuf *iobuf)
 3456 {
 3457     /*
 3458     struct fuse_open_in *foi = msg;
 3459      */
 3460 
 3461     fuse_state_t *state = NULL;
 3462 
 3463     GET_STATE(this, finh, state);
 3464 
 3465     fuse_resolve_inode_init(state, &state->resolve, finh->nodeid);
 3466 
 3467     fuse_resolve_and_resume(state, fuse_opendir_resume);
 3468 }
 3469 
 3470 unsigned char
 3471 d_type_from_stat(struct iatt *buf)
 3472 {
 3473     unsigned char d_type;
 3474 
 3475     if (IA_ISLNK(buf->ia_type)) {
 3476         d_type = DT_LNK;
 3477 
 3478     } else if (IA_ISDIR(buf->ia_type)) {
 3479         d_type = DT_DIR;
 3480 
 3481     } else if (IA_ISFIFO(buf->ia_type)) {
 3482         d_type = DT_FIFO;
 3483 
 3484     } else if (IA_ISSOCK(buf->ia_type)) {
 3485         d_type = DT_SOCK;
 3486 
 3487     } else if (IA_ISCHR(buf->ia_type)) {
 3488         d_type = DT_CHR;
 3489 
 3490     } else if (IA_ISBLK(buf->ia_type)) {
 3491         d_type = DT_BLK;
 3492 
 3493     } else if (IA_ISREG(buf->ia_type)) {
 3494         d_type = DT_REG;
 3495 
 3496     } else {
 3497         d_type = DT_UNKNOWN;
 3498     }
 3499 
 3500     return d_type;
 3501 }
 3502 
 3503 static int
 3504 fuse_readdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3505                  int32_t op_ret, int32_t op_errno, gf_dirent_t *entries,
 3506                  dict_t *xdata)
 3507 {
 3508     fuse_state_t *state = NULL;
 3509     fuse_in_header_t *finh = NULL;
 3510     size_t size = 0;
 3511     size_t max_size = 0;
 3512     char *buf = NULL;
 3513     gf_dirent_t *entry = NULL;
 3514     struct fuse_dirent *fde = NULL;
 3515     fuse_private_t *priv = NULL;
 3516 
 3517     state = frame->root->state;
 3518     finh = state->finh;
 3519     priv = state->this->private;
 3520 
 3521     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 3522 
 3523     if (op_ret < 0) {
 3524         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 3525                "%" PRIu64 ": READDIR => -1 (%s)", frame->root->unique,
 3526                strerror(op_errno));
 3527 
 3528         send_fuse_err(this, finh, op_errno);
 3529         goto out;
 3530     }
 3531 
 3532     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 3533            "%" PRIu64 ": READDIR => %d/%" GF_PRI_SIZET ",%" PRId64,
 3534            frame->root->unique, op_ret, state->size, state->off);
 3535 
 3536     list_for_each_entry(entry, &entries->list, list)
 3537     {
 3538         size_t fde_size = FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET +
 3539                                             strlen(entry->d_name));
 3540         max_size += fde_size;
 3541 
 3542         if (max_size > state->size) {
 3543             /* we received too many entries to fit in the reply */
 3544             max_size -= fde_size;
 3545             break;
 3546         }
 3547     }
 3548 
 3549     if (max_size == 0) {
 3550         send_fuse_data(this, finh, 0, 0);
 3551         goto out;
 3552     }
 3553 
 3554     buf = GF_CALLOC(1, max_size, gf_fuse_mt_char);
 3555     if (!buf) {
 3556         gf_log("glusterfs-fuse", GF_LOG_DEBUG,
 3557                "%" PRIu64 ": READDIR => -1 (%s)", frame->root->unique,
 3558                strerror(ENOMEM));
 3559         send_fuse_err(this, finh, ENOMEM);
 3560         goto out;
 3561     }
 3562 
 3563     size = 0;
 3564     list_for_each_entry(entry, &entries->list, list)
 3565     {
 3566         fde = (struct fuse_dirent *)(buf + size);
 3567         gf_fuse_fill_dirent(entry, fde, priv->enable_ino32);
 3568         size += FUSE_DIRENT_SIZE(fde);
 3569 
 3570         if (size == max_size)
 3571             break;
 3572     }
 3573 
 3574     send_fuse_data(this, finh, buf, size);
 3575 
 3576     /* TODO: */
 3577     /* gf_link_inodes_from_dirent (this, state->fd->inode, entries); */
 3578 
 3579 out:
 3580     free_fuse_state(state);
 3581     STACK_DESTROY(frame->root);
 3582     GF_FREE(buf);
 3583     return 0;
 3584 }
 3585 
 3586 void
 3587 fuse_readdir_resume(fuse_state_t *state)
 3588 {
 3589     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 3590            "%" PRIu64 ": READDIR (%p, size=%" GF_PRI_SIZET ", offset=%" PRId64
 3591            ")",
 3592            state->finh->unique, state->fd, state->size, state->off);
 3593 
 3594     FUSE_FOP(state, fuse_readdir_cbk, GF_FOP_READDIR, readdir, state->fd,
 3595              state->size, state->off, state->xdata);
 3596 }
 3597 
 3598 static void
 3599 fuse_readdir(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3600              struct iobuf *iobuf)
 3601 {
 3602     struct fuse_read_in *fri = msg;
 3603 
 3604     fuse_state_t *state = NULL;
 3605     fd_t *fd = NULL;
 3606 
 3607     GET_STATE(this, finh, state);
 3608     state->size = fri->size;
 3609     state->off = fri->offset;
 3610     fd = FH_TO_FD(fri->fh);
 3611     state->fd = fd;
 3612 
 3613     fuse_resolve_fd_init(state, &state->resolve, fd);
 3614 
 3615     fuse_resolve_and_resume(state, fuse_readdir_resume);
 3616 }
 3617 
 3618 #if FUSE_KERNEL_MINOR_VERSION >= 20
 3619 static int
 3620 fuse_readdirp_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3621                   int32_t op_ret, int32_t op_errno, gf_dirent_t *entries,
 3622                   dict_t *xdata)
 3623 {
 3624     fuse_state_t *state = NULL;
 3625     fuse_in_header_t *finh = NULL;
 3626     size_t max_size = 0;
 3627     size_t size = 0;
 3628     char *buf = NULL;
 3629     gf_dirent_t *entry = NULL;
 3630     struct fuse_direntplus *fde = NULL;
 3631     struct fuse_entry_out *feo = NULL;
 3632     fuse_private_t *priv = NULL;
 3633 
 3634     state = frame->root->state;
 3635     finh = state->finh;
 3636     priv = this->private;
 3637 
 3638     if (op_ret < 0) {
 3639         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 3640                "%" PRIu64 ": READDIRP => -1 (%s)", frame->root->unique,
 3641                strerror(op_errno));
 3642 
 3643         send_fuse_err(this, finh, op_errno);
 3644         goto out;
 3645     }
 3646 
 3647     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 3648            "%" PRIu64 ": READDIRP => %d/%" GF_PRI_SIZET ",%" PRId64,
 3649            frame->root->unique, op_ret, state->size, state->off);
 3650 
 3651     list_for_each_entry(entry, &entries->list, list)
 3652     {
 3653         size_t fdes = FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS +
 3654                                         strlen(entry->d_name));
 3655         max_size += fdes;
 3656 
 3657         if (max_size > state->size) {
 3658             /* we received too many entries to fit in the reply */
 3659             max_size -= fdes;
 3660             break;
 3661         }
 3662     }
 3663 
 3664     if (max_size == 0) {
 3665         send_fuse_data(this, finh, 0, 0);
 3666         goto out;
 3667     }
 3668 
 3669     buf = GF_CALLOC(1, max_size, gf_fuse_mt_char);
 3670     if (!buf) {
 3671         gf_log("glusterfs-fuse", GF_LOG_DEBUG,
 3672                "%" PRIu64 ": READDIRP => -1 (%s)", frame->root->unique,
 3673                strerror(ENOMEM));
 3674         send_fuse_err(this, finh, ENOMEM);
 3675         goto out;
 3676     }
 3677 
 3678     size = 0;
 3679     list_for_each_entry(entry, &entries->list, list)
 3680     {
 3681         inode_t *linked_inode;
 3682 
 3683         fde = (struct fuse_direntplus *)(buf + size);
 3684         feo = &fde->entry_out;
 3685 
 3686         if (priv->enable_ino32)
 3687             fde->dirent.ino = GF_FUSE_SQUASH_INO(entry->d_ino);
 3688         else
 3689             fde->dirent.ino = entry->d_ino;
 3690 
 3691         fde->dirent.off = entry->d_off;
 3692         fde->dirent.type = entry->d_type;
 3693         fde->dirent.namelen = strlen(entry->d_name);
 3694         (void)memcpy(fde->dirent.name, entry->d_name, fde->dirent.namelen);
 3695         size += FUSE_DIRENTPLUS_SIZE(fde);
 3696 
 3697         if (!entry->inode)
 3698             goto next_entry;
 3699 
 3700         entry->d_stat.ia_blksize = this->ctx->page_size;
 3701         gf_fuse_stat2attr(&entry->d_stat, &feo->attr, priv->enable_ino32);
 3702 
 3703         linked_inode = inode_link(entry->inode, state->fd->inode, entry->d_name,
 3704                                   &entry->d_stat);
 3705         if (!linked_inode)
 3706             goto next_entry;
 3707 
 3708         if (entry->inode != linked_inode) {
 3709             memset(&entry->d_stat, 0, sizeof(entry->d_stat));
 3710         }
 3711 
 3712         feo->nodeid = inode_to_fuse_nodeid(linked_inode);
 3713 
 3714         if (!((strcmp(entry->d_name, ".") == 0) ||
 3715               (strcmp(entry->d_name, "..") == 0))) {
 3716             inode_lookup(linked_inode);
 3717         }
 3718 
 3719         inode_unref(linked_inode);
 3720 
 3721         feo->entry_valid = calc_timeout_sec(priv->entry_timeout);
 3722         feo->entry_valid_nsec = calc_timeout_nsec(priv->entry_timeout);
 3723 
 3724         if (entry->d_stat.ia_ctime) {
 3725             feo->attr_valid = calc_timeout_sec(priv->attribute_timeout);
 3726             feo->attr_valid_nsec = calc_timeout_nsec(priv->attribute_timeout);
 3727         } else {
 3728             feo->attr_valid = feo->attr_valid_nsec = 0;
 3729         }
 3730 
 3731     next_entry:
 3732         if (size == max_size)
 3733             break;
 3734     }
 3735 
 3736     send_fuse_data(this, finh, buf, size);
 3737 out:
 3738     free_fuse_state(state);
 3739     STACK_DESTROY(frame->root);
 3740     GF_FREE(buf);
 3741     return 0;
 3742 }
 3743 
 3744 void
 3745 fuse_readdirp_resume(fuse_state_t *state)
 3746 {
 3747     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 3748            "%" PRIu64 ": READDIRP (%p, size=%" GF_PRI_SIZET ", offset=%" PRId64
 3749            ")",
 3750            state->finh->unique, state->fd, state->size, state->off);
 3751 
 3752     FUSE_FOP(state, fuse_readdirp_cbk, GF_FOP_READDIRP, readdirp, state->fd,
 3753              state->size, state->off, state->xdata);
 3754 }
 3755 
 3756 static void
 3757 fuse_readdirp(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3758               struct iobuf *iobuf)
 3759 {
 3760     struct fuse_read_in *fri = msg;
 3761 
 3762     fuse_state_t *state = NULL;
 3763     fd_t *fd = NULL;
 3764 
 3765     GET_STATE(this, finh, state);
 3766     state->size = fri->size;
 3767     state->off = fri->offset;
 3768     fd = FH_TO_FD(fri->fh);
 3769     state->fd = fd;
 3770 
 3771     fuse_resolve_fd_init(state, &state->resolve, fd);
 3772 
 3773     fuse_resolve_and_resume(state, fuse_readdirp_resume);
 3774 }
 3775 #endif
 3776 
 3777 #if FUSE_KERNEL_MINOR_VERSION >= 19
 3778 #ifdef FALLOC_FL_KEEP_SIZE
 3779 static int
 3780 fuse_fallocate_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3781                    int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
 3782                    struct iatt *postbuf, dict_t *xdata)
 3783 {
 3784     return fuse_err_cbk(frame, cookie, this, op_ret, op_errno, xdata);
 3785 }
 3786 
 3787 static void
 3788 fuse_fallocate_resume(fuse_state_t *state)
 3789 {
 3790     gf_log(
 3791         "glusterfs-fuse", GF_LOG_TRACE,
 3792         "%" PRIu64 ": FALLOCATE (%p, flags=%d, size=%zu, offset=%" PRId64 ")",
 3793         state->finh->unique, state->fd, state->flags, state->size, state->off);
 3794 
 3795     if (state->flags & FALLOC_FL_PUNCH_HOLE)
 3796         FUSE_FOP(state, fuse_fallocate_cbk, GF_FOP_DISCARD, discard, state->fd,
 3797                  state->off, state->size, state->xdata);
 3798     else
 3799         FUSE_FOP(state, fuse_fallocate_cbk, GF_FOP_FALLOCATE, fallocate,
 3800                  state->fd, (state->flags & FALLOC_FL_KEEP_SIZE), state->off,
 3801                  state->size, state->xdata);
 3802 }
 3803 
 3804 static void
 3805 fuse_fallocate(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3806                struct iobuf *iobuf)
 3807 {
 3808     struct fuse_fallocate_in *ffi = msg;
 3809     fuse_state_t *state = NULL;
 3810 
 3811     GET_STATE(this, finh, state);
 3812     state->off = ffi->offset;
 3813     state->size = ffi->length;
 3814     state->flags = ffi->mode;
 3815     state->fd = FH_TO_FD(ffi->fh);
 3816 
 3817     fuse_resolve_fd_init(state, &state->resolve, state->fd);
 3818     fuse_resolve_and_resume(state, fuse_fallocate_resume);
 3819 }
 3820 #endif /* FALLOC_FL_KEEP_SIZE */
 3821 #endif /* FUSE minor version >= 19 */
 3822 
 3823 static void
 3824 fuse_releasedir(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3825                 struct iobuf *iobuf)
 3826 {
 3827     struct fuse_release_in *fri = msg;
 3828     fuse_state_t *state = NULL;
 3829     fuse_private_t *priv = NULL;
 3830 
 3831     GET_STATE(this, finh, state);
 3832     state->fd = FH_TO_FD(fri->fh);
 3833     if (!state->fd)
 3834         goto out;
 3835 
 3836     priv = this->private;
 3837 
 3838     fuse_log_eh(this,
 3839                 "RELEASEDIR (): finh->unique: %" PRIu64 ": fd: %p, gfid: %s",
 3840                 finh->unique, state->fd, uuid_utoa(state->fd->inode->gfid));
 3841 
 3842     gf_log("glusterfs-fuse", GF_LOG_TRACE,
 3843            "finh->unique: %" PRIu64 ": RELEASEDIR %p", finh->unique, state->fd);
 3844 
 3845     fuse_fd_ctx_destroy(this, state->fd);
 3846     fd_unref(state->fd);
 3847 
 3848     gf_fdptr_put(priv->fdtable, state->fd);
 3849 
 3850     state->fd = NULL;
 3851 
 3852 out:
 3853     send_fuse_err(this, finh, 0);
 3854 
 3855     free_fuse_state(state);
 3856 
 3857     return;
 3858 }
 3859 
 3860 void
 3861 fuse_fsyncdir_resume(fuse_state_t *state)
 3862 {
 3863     FUSE_FOP(state, fuse_err_cbk, GF_FOP_FSYNCDIR, fsyncdir, state->fd,
 3864              (state->flags & 1), state->xdata);
 3865 }
 3866 
 3867 static void
 3868 fuse_fsyncdir(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3869               struct iobuf *iobuf)
 3870 {
 3871     struct fuse_fsync_in *fsi = msg;
 3872 
 3873     fuse_state_t *state = NULL;
 3874     fd_t *fd = NULL;
 3875 
 3876     fd = FH_TO_FD(fsi->fh);
 3877 
 3878     GET_STATE(this, finh, state);
 3879     state->fd = fd;
 3880 
 3881     fuse_resolve_fd_init(state, &state->resolve, fd);
 3882 
 3883     state->flags = fsi->fsync_flags;
 3884     fuse_resolve_and_resume(state, fuse_fsyncdir_resume);
 3885 
 3886     return;
 3887 }
 3888 
 3889 static int
 3890 fuse_statfs_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 3891                 int32_t op_ret, int32_t op_errno, struct statvfs *buf,
 3892                 dict_t *xdata)
 3893 {
 3894     fuse_state_t *state = NULL;
 3895     fuse_in_header_t *finh = NULL;
 3896     fuse_private_t *priv = NULL;
 3897     struct fuse_statfs_out fso = {
 3898         {
 3899             0,
 3900         },
 3901     };
 3902 
 3903     state = frame->root->state;
 3904     priv = this->private;
 3905     finh = state->finh;
 3906 
 3907     fuse_log_eh(this, "op_ret: %d, op_errno: %d, %" PRIu64 ": %s()", op_ret,
 3908                 op_errno, frame->root->unique, gf_fop_list[frame->root->op]);
 3909 
 3910     if (op_ret == 0) {
 3911         fso.st.bsize = buf->f_bsize;
 3912         fso.st.frsize = buf->f_frsize;
 3913         fso.st.blocks = buf->f_blocks;
 3914         fso.st.bfree = buf->f_bfree;
 3915         fso.st.bavail = buf->f_bavail;
 3916         fso.st.files = buf->f_files;
 3917         fso.st.ffree = buf->f_ffree;
 3918         fso.st.namelen = buf->f_namemax;
 3919 
 3920         priv->proto_minor >= 4
 3921             ? send_fuse_obj(this, finh, &fso)
 3922             : send_fuse_data(this, finh, &fso, FUSE_COMPAT_STATFS_SIZE);
 3923     } else {
 3924         /* facilitate retry from VFS */
 3925         if (op_errno == ENOENT)
 3926             op_errno = ESTALE;
 3927 
 3928         gf_log("glusterfs-fuse", GF_LOG_WARNING, "%" PRIu64 ": ERR => -1 (%s)",
 3929                frame->root->unique, strerror(op_errno));
 3930 
 3931         send_fuse_err(this, finh, op_errno);
 3932     }
 3933 
 3934     free_fuse_state(state);
 3935     STACK_DESTROY(frame->root);
 3936 
 3937     return 0;
 3938 }
 3939 
 3940 void
 3941 fuse_statfs_resume(fuse_state_t *state)
 3942 {
 3943     if (!state->loc.inode) {
 3944         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 3945                "%" PRIu64 ": STATFS (%s) resolution fail", state->finh->unique,
 3946                uuid_utoa(state->resolve.gfid));
 3947 
 3948         /* facilitate retry from VFS */
 3949         if (state->resolve.op_errno == ENOENT)
 3950             state->resolve.op_errno = ESTALE;
 3951 
 3952         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 3953         free_fuse_state(state);
 3954         return;
 3955     }
 3956 
 3957     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": STATFS",
 3958            state->finh->unique);
 3959 
 3960     FUSE_FOP(state, fuse_statfs_cbk, GF_FOP_STATFS, statfs, &state->loc,
 3961              state->xdata);
 3962 }
 3963 
 3964 static void
 3965 fuse_statfs(xlator_t *this, fuse_in_header_t *finh, void *msg,
 3966             struct iobuf *iobuf)
 3967 {
 3968     fuse_state_t *state = NULL;
 3969 
 3970     GET_STATE(this, finh, state);
 3971 
 3972     fuse_resolve_inode_init(state, &state->resolve, finh->nodeid);
 3973 
 3974     fuse_resolve_and_resume(state, fuse_statfs_resume);
 3975 }
 3976 
 3977 void
 3978 fuse_setxattr_resume(fuse_state_t *state)
 3979 {
 3980     if (!state->loc.inode) {
 3981         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 3982                "%" PRIu64 ": SETXATTR %s/%" PRIu64
 3983                " (%s) "
 3984                "resolution failed",
 3985                state->finh->unique, uuid_utoa(state->resolve.gfid),
 3986                state->finh->nodeid, state->name);
 3987 
 3988         /* facilitate retry from VFS */
 3989         if (state->resolve.op_errno == ENOENT)
 3990             state->resolve.op_errno = ESTALE;
 3991 
 3992         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 3993         free_fuse_state(state);
 3994         return;
 3995     }
 3996 
 3997 #ifdef GF_TEST_FFOP
 3998     state->fd = fd_lookup(state->loc.inode, state->finh->pid);
 3999 #endif /* GF_TEST_FFOP */
 4000 
 4001     if (state->fd) {
 4002         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 4003                "%" PRIu64 ": SETXATTR %p/%" PRIu64 " (%s)", state->finh->unique,
 4004                state->fd, state->finh->nodeid, state->name);
 4005 
 4006         FUSE_FOP(state, fuse_setxattr_cbk, GF_FOP_FSETXATTR, fsetxattr,
 4007                  state->fd, state->xattr, state->flags, state->xdata);
 4008     } else {
 4009         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 4010                "%" PRIu64 ": SETXATTR %s/%" PRIu64 " (%s)", state->finh->unique,
 4011                state->loc.path, state->finh->nodeid, state->name);
 4012 
 4013         FUSE_FOP(state, fuse_setxattr_cbk, GF_FOP_SETXATTR, setxattr,
 4014                  &state->loc, state->xattr, state->flags, state->xdata);
 4015     }
 4016 }
 4017 
 4018 static void
 4019 fuse_setxattr(xlator_t *this, fuse_in_header_t *finh, void *msg,
 4020               struct iobuf *iobuf)
 4021 {
 4022     struct fuse_setxattr_in *fsi = msg;
 4023     char *name = (char *)(fsi + 1);
 4024     char *value = name + strlen(name) + 1;
 4025     struct fuse_private *priv = NULL;
 4026 
 4027     fuse_state_t *state = NULL;
 4028     char *dict_value = NULL;
 4029     int32_t ret = -1;
 4030     int32_t op_errno = 0;
 4031     char *newkey = NULL;
 4032 
 4033     priv = this->private;
 4034 
 4035     GET_STATE(this, finh, state);
 4036 
 4037 #ifdef GF_DARWIN_HOST_OS
 4038     if (fsi->position) {
 4039         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 4040                "%" PRIu64 ": SETXATTR %s/%" PRIu64
 4041                " (%s):"
 4042                "refusing positioned setxattr",
 4043                finh->unique, state->loc.path, finh->nodeid, name);
 4044         op_errno = EINVAL;
 4045         goto done;
 4046     }
 4047 #endif
 4048 
 4049     if (fuse_ignore_xattr_set(priv, name)) {
 4050         goto done;
 4051     }
 4052 
 4053     if (!priv->acl) {
 4054         if ((strcmp(name, POSIX_ACL_ACCESS_XATTR) == 0) ||
 4055             (strcmp(name, POSIX_ACL_DEFAULT_XATTR) == 0)) {
 4056             op_errno = EOPNOTSUPP;
 4057             goto done;
 4058         }
 4059     }
 4060 
 4061     ret = fuse_check_selinux_cap_xattr(priv, name);
 4062     if (ret) {
 4063         op_errno = EOPNOTSUPP;
 4064         goto done;
 4065     }
 4066 
 4067     /* Check if the command is for changing the log
 4068        level of process or specific xlator */
 4069     ret = is_gf_log_command(this, name, value, fsi->size);
 4070     if (ret >= 0) {
 4071         op_errno = ret;
 4072         goto done;
 4073     }
 4074 
 4075     if (!strcmp("inode-invalidate", name)) {
 4076         gf_log("fuse", GF_LOG_TRACE, "got request to invalidate %" PRIu64,
 4077                finh->nodeid);
 4078 #if FUSE_KERNEL_MINOR_VERSION >= 11
 4079         fuse_invalidate_entry(this, finh->nodeid);
 4080 #endif
 4081         goto done;
 4082     }
 4083 
 4084     if (!strcmp(GFID_XATTR_KEY, name) || !strcmp(GF_XATTR_VOL_ID_KEY, name)) {
 4085         op_errno = EPERM;
 4086         goto done;
 4087     }
 4088 
 4089     state->size = fsi->size;
 4090 
 4091     fuse_resolve_inode_init(state, &state->resolve, finh->nodeid);
 4092 
 4093     state->xattr = dict_new();
 4094     if (!state->xattr) {
 4095         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 4096                "%" PRIu64 ": SETXATTR dict allocation failed", finh->unique);
 4097         op_errno = ENOMEM;
 4098         goto done;
 4099     }
 4100 
 4101     ret = fuse_flip_xattr_ns(priv, name, &newkey);
 4102     if (ret) {
 4103         op_errno = ENOMEM;
 4104         goto done;
 4105     }
 4106 
 4107     if (fsi->size > 0) {
 4108         /*
 4109          * Many translators expect setxattr values to be strings, but
 4110          * neither dict_get_str nor data_to_str do any checking or
 4111          * fixups to make sure that's the case.  To avoid nasty
 4112          * surprises, allocate an extra byte and add a NUL here.
 4113          */
 4114         dict_value = GF_MALLOC(fsi->size + 1, gf_common_mt_char);
 4115         if (dict_value == NULL) {
 4116             gf_log("glusterfs-fuse", GF_LOG_ERROR,
 4117                    "%" PRIu64 ": SETXATTR value allocation failed",
 4118                    finh->unique);
 4119             op_errno = ENOMEM;
 4120             goto done;
 4121         }
 4122         memcpy(dict_value, value, fsi->size);
 4123         dict_value[fsi->size] = '\0';
 4124     }
 4125     ret = dict_set_dynptr(state->xattr, newkey, dict_value, fsi->size);
 4126     if (ret < 0) {
 4127         op_errno = -ret;
 4128         GF_FREE(dict_value);
 4129         GF_FREE(newkey);
 4130         goto done;
 4131     }
 4132 
 4133     state->flags = fsi->flags;
 4134     state->name = newkey;
 4135 
 4136     fuse_resolve_and_resume(state, fuse_setxattr_resume);
 4137 
 4138     return;
 4139 
 4140 done:
 4141     send_fuse_err(this, finh, op_errno);
 4142     free_fuse_state(state);
 4143 }
 4144 
 4145 static void
 4146 send_fuse_xattr(xlator_t *this, fuse_in_header_t *finh, const char *value,
 4147                 size_t size, size_t expected)
 4148 {
 4149     struct fuse_getxattr_out fgxo;
 4150 
 4151     /* linux kernel limits the size of xattr value to 64k */
 4152     if (size > GLUSTERFS_XATTR_LEN_MAX)
 4153         send_fuse_err(this, finh, E2BIG);
 4154     else if (expected) {
 4155         /* if callback for getxattr and asks for value */
 4156         if (size > expected)
 4157             /* reply would be bigger than
 4158              * what was asked by kernel */
 4159             send_fuse_err(this, finh, ERANGE);
 4160         else
 4161             send_fuse_data(this, finh, (void *)value, size);
 4162     } else {
 4163         fgxo.size = size;
 4164         send_fuse_obj(this, finh, &fgxo);
 4165     }
 4166 }
 4167 
 4168 /* filter out xattrs that need not be visible on the
 4169  * mount point. this is _specifically_ for geo-rep
 4170  * as of now, to prevent Rsync from crying out loud
 4171  * when it tries to setxattr() for selinux xattrs
 4172  */
 4173 static int
 4174 fuse_filter_xattr(char *key)
 4175 {
 4176     int need_filter = 0;
 4177     struct fuse_private *priv = THIS->private;
 4178 
 4179     if ((priv->client_pid == GF_CLIENT_PID_GSYNCD) &&
 4180         fnmatch("*.selinux*", key, FNM_PERIOD) == 0)
 4181         need_filter = 1;
 4182 
 4183     return need_filter;
 4184 }
 4185 
 4186 static int
 4187 fuse_xattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 4188                int32_t op_ret, int32_t op_errno, dict_t *dict, dict_t *xdata)
 4189 {
 4190     char *value = "";
 4191     fuse_state_t *state = NULL;
 4192     fuse_in_header_t *finh = NULL;
 4193     data_t *value_data = NULL;
 4194     int ret = -1;
 4195     int32_t len = 0;
 4196     int32_t len_next = 0;
 4197 
 4198     state = frame->root->state;
 4199     finh = state->finh;
 4200 
 4201     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 4202 
 4203     if (op_ret >= 0) {
 4204         gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": %s() %s => %d",
 4205                frame->root->unique, gf_fop_list[frame->root->op],
 4206                state->loc.path, op_ret);
 4207 
 4208         /* if successful */
 4209         if (state->name) {
 4210             /* if callback for getxattr */
 4211             value_data = dict_get(dict, state->name);
 4212             if (value_data) {
 4213                 ret = value_data->len; /* Don't return the value for '\0' */
 4214                 value = value_data->data;
 4215 
 4216                 send_fuse_xattr(this, finh, value, ret, state->size);
 4217                 /* if(ret >...)...else if...else */
 4218             } else {
 4219                 send_fuse_err(this, finh, ENODATA);
 4220             } /* if(value_data)...else */
 4221         } else {
 4222             /* if callback for listxattr */
 4223             /* we need to invoke fuse_filter_xattr() twice. Once
 4224              * while counting size and then while filling buffer
 4225              */
 4226             len = dict_keys_join(NULL, 0, dict, fuse_filter_xattr);
 4227             if (len < 0)
 4228                 goto out;
 4229 
 4230             value = alloca(len + 1);
 4231             if (!value)
 4232                 goto out;
 4233 
 4234             len_next = dict_keys_join(value, len, dict, fuse_filter_xattr);
 4235             if (len_next != len)
 4236                 gf_log(THIS->name, GF_LOG_ERROR, "sizes not equal %d != %d",
 4237                        len, len_next);
 4238 
 4239             send_fuse_xattr(this, finh, value, len, state->size);
 4240         } /* if(state->name)...else */
 4241     } else {
 4242         /* facilitate retry from VFS */
 4243         if ((state->fd == NULL) && (op_errno == ENOENT)) {
 4244             op_errno = ESTALE;
 4245         }
 4246 
 4247         /* if failure - no need to check if listxattr or getxattr */
 4248         if (op_errno != ENODATA && op_errno != ENOATTR) {
 4249             if (op_errno == ENOTSUP) {
 4250                 GF_LOG_OCCASIONALLY(gf_fuse_xattr_enotsup_log, "glusterfs-fuse",
 4251                                     GF_LOG_ERROR,
 4252                                     "extended attribute not "
 4253                                     "supported by the backend "
 4254                                     "storage");
 4255             } else {
 4256                 gf_log("glusterfs-fuse", GF_LOG_WARNING,
 4257                        "%" PRIu64 ": %s(%s) %s => -1 (%s)", frame->root->unique,
 4258                        gf_fop_list[frame->root->op], state->name,
 4259                        state->loc.path, strerror(op_errno));
 4260             }
 4261         } else {
 4262             gf_log("glusterfs-fuse", GF_LOG_DEBUG,
 4263                    "%" PRIu64 ": %s(%s) %s => -1 (%s)", frame->root->unique,
 4264                    gf_fop_list[frame->root->op], state->name, state->loc.path,
 4265                    strerror(op_errno));
 4266         } /* if(op_errno!= ENODATA)...else */
 4267 
 4268         send_fuse_err(this, finh, op_errno);
 4269     } /* if(op_ret>=0)...else */
 4270 
 4271 out:
 4272     free_fuse_state(state);
 4273     STACK_DESTROY(frame->root);
 4274 
 4275     return 0;
 4276 }
 4277 
 4278 void
 4279 fuse_getxattr_resume(fuse_state_t *state)
 4280 {
 4281     char *value = NULL;
 4282 
 4283     if (!state->loc.inode) {
 4284         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 4285                "%" PRIu64 ": GETXATTR %s/%" PRIu64
 4286                " (%s) "
 4287                "resolution failed",
 4288                state->finh->unique, uuid_utoa(state->resolve.gfid),
 4289                state->finh->nodeid, state->name);
 4290 
 4291         /* facilitate retry from VFS */
 4292         if (state->resolve.op_errno == ENOENT)
 4293             state->resolve.op_errno = ESTALE;
 4294 
 4295         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 4296         free_fuse_state(state);
 4297         return;
 4298     }
 4299 
 4300 #ifdef GF_TEST_FFOP
 4301     state->fd = fd_lookup(state->loc.inode, state->finh->pid);
 4302 #endif /* GF_TEST_FFOP */
 4303 
 4304     if (state->name && (strcmp(state->name, VIRTUAL_GFID_XATTR_KEY) == 0)) {
 4305         /* send glusterfs gfid in binary form */
 4306 
 4307         value = GF_MALLOC(16 + 1, gf_common_mt_char);
 4308         if (!value) {
 4309             send_fuse_err(state->this, state->finh, ENOMEM);
 4310             goto internal_out;
 4311         }
 4312         memcpy(value, state->loc.inode->gfid, 16);
 4313         value[16] = '\0';
 4314 
 4315         send_fuse_xattr(THIS, state->finh, value, 16, state->size);
 4316         GF_FREE(value);
 4317     internal_out:
 4318         free_fuse_state(state);
 4319         return;
 4320     }
 4321 
 4322     if (state->name && (strcmp(state->name, VIRTUAL_GFID_XATTR_KEY_STR) == 0)) {
 4323         /* transform binary gfid to canonical form */
 4324 
 4325         value = GF_CALLOC(UUID_CANONICAL_FORM_LEN + 1, sizeof(char),
 4326                           gf_common_mt_char);
 4327         if (!value) {
 4328             send_fuse_err(state->this, state->finh, ENOMEM);
 4329             goto internal_out1;
 4330         }
 4331         uuid_utoa_r(state->loc.inode->gfid, value);
 4332 
 4333         send_fuse_xattr(THIS, state->finh, value, UUID_CANONICAL_FORM_LEN,
 4334                         state->size);
 4335         GF_FREE(value);
 4336     internal_out1:
 4337         free_fuse_state(state);
 4338         return;
 4339     }
 4340 
 4341     if (state->fd) {
 4342         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 4343                "%" PRIu64 ": GETXATTR %p/%" PRIu64 " (%s)", state->finh->unique,
 4344                state->fd, state->finh->nodeid, state->name);
 4345 
 4346         FUSE_FOP(state, fuse_xattr_cbk, GF_FOP_FGETXATTR, fgetxattr, state->fd,
 4347                  state->name, state->xdata);
 4348     } else {
 4349         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 4350                "%" PRIu64 ": GETXATTR %s/%" PRIu64 " (%s)", state->finh->unique,
 4351                state->loc.path, state->finh->nodeid, state->name);
 4352 
 4353         FUSE_FOP(state, fuse_xattr_cbk, GF_FOP_GETXATTR, getxattr, &state->loc,
 4354                  state->name, state->xdata);
 4355     }
 4356 }
 4357 
 4358 static void
 4359 fuse_getxattr(xlator_t *this, fuse_in_header_t *finh, void *msg,
 4360               struct iobuf *iobuf)
 4361 {
 4362     struct fuse_getxattr_in *fgxi = msg;
 4363     char *name = (char *)(fgxi + 1);
 4364     fuse_state_t *state = NULL;
 4365     struct fuse_private *priv = NULL;
 4366     int rv = 0;
 4367     int op_errno = EINVAL;
 4368     char *newkey = NULL;
 4369     int ret = 0;
 4370 
 4371     priv = this->private;
 4372     GET_STATE(this, finh, state);
 4373 
 4374 #ifdef GF_DARWIN_HOST_OS
 4375     if (fgxi->position) {
 4376         /* position can be used only for
 4377          * resource fork queries which we
 4378          * don't support anyway... so handling
 4379          * it separately is just sort of a
 4380          * matter of aesthetics, not strictly
 4381          * necessary.
 4382          */
 4383 
 4384         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 4385                "%" PRIu64 ": GETXATTR %s/%" PRIu64
 4386                " (%s):"
 4387                "refusing positioned getxattr",
 4388                finh->unique, state->loc.path, finh->nodeid, name);
 4389         op_errno = EINVAL;
 4390         goto err;
 4391     }
 4392 #endif
 4393 
 4394     if (!priv->acl) {
 4395         if ((strcmp(name, POSIX_ACL_ACCESS_XATTR) == 0) ||
 4396             (strcmp(name, POSIX_ACL_DEFAULT_XATTR) == 0)) {
 4397             op_errno = ENOTSUP;
 4398             goto err;
 4399         }
 4400     }
 4401 
 4402     ret = fuse_check_selinux_cap_xattr(priv, name);
 4403     if (ret) {
 4404         op_errno = ENODATA;
 4405         goto err;
 4406     }
 4407 
 4408     fuse_resolve_inode_init(state, &state->resolve, finh->nodeid);
 4409 
 4410     rv = fuse_flip_xattr_ns(priv, name, &newkey);
 4411     if (rv) {
 4412         op_errno = ENOMEM;
 4413         goto err;
 4414     }
 4415 
 4416     state->size = fgxi->size;
 4417     state->name = newkey;
 4418 
 4419     fuse_resolve_and_resume(state, fuse_getxattr_resume);
 4420 
 4421     return;
 4422 err:
 4423     send_fuse_err(this, finh, op_errno);
 4424     free_fuse_state(state);
 4425     return;
 4426 }
 4427 
 4428 void
 4429 fuse_listxattr_resume(fuse_state_t *state)
 4430 {
 4431     if (!state->loc.inode) {
 4432         gf_log("glusterfs-fuse", GF_LOG_WARNING,
 4433                "%" PRIu64 ": LISTXATTR %s/%" PRIu64 "resolution failed",
 4434                state->finh->unique, uuid_utoa(state->resolve.gfid),
 4435                state->finh->nodeid);
 4436 
 4437         /* facilitate retry from VFS */
 4438         if (state->resolve.op_errno == ENOENT)
 4439             state->resolve.op_errno = ESTALE;
 4440 
 4441         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 4442         free_fuse_state(state);
 4443         return;
 4444     }
 4445 
 4446 #ifdef GF_TEST_FFOP
 4447     state->fd = fd_lookup(state->loc.inode, state->finh->pid);
 4448 #endif /* GF_TEST_FFOP */
 4449 
 4450     if (state->fd) {
 4451         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 4452                "%" PRIu64 ": LISTXATTR %p/%" PRIu64, state->finh->unique,
 4453                state->fd, state->finh->nodeid);
 4454 
 4455         FUSE_FOP(state, fuse_xattr_cbk, GF_FOP_FGETXATTR, fgetxattr, state->fd,
 4456                  NULL, state->xdata);
 4457     } else {
 4458         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 4459                "%" PRIu64 ": LISTXATTR %s/%" PRIu64, state->finh->unique,
 4460                state->loc.path, state->finh->nodeid);
 4461 
 4462         FUSE_FOP(state, fuse_xattr_cbk, GF_FOP_GETXATTR, getxattr, &state->loc,
 4463                  NULL, state->xdata);
 4464     }
 4465 }
 4466 
 4467 static void
 4468 fuse_listxattr(xlator_t *this, fuse_in_header_t *finh, void *msg,
 4469                struct iobuf *iobuf)
 4470 {
 4471     struct fuse_getxattr_in *fgxi = msg;
 4472     fuse_state_t *state = NULL;
 4473 
 4474     GET_STATE(this, finh, state);
 4475 
 4476     fuse_resolve_inode_init(state, &state->resolve, finh->nodeid);
 4477 
 4478     state->size = fgxi->size;
 4479 
 4480     fuse_resolve_and_resume(state, fuse_listxattr_resume);
 4481 
 4482     return;
 4483 }
 4484 
 4485 void
 4486 fuse_removexattr_resume(fuse_state_t *state)
 4487 {
 4488     if (!state->loc.inode) {
 4489         gf_log("glusterfs-fuse", GF_LOG_DEBUG,
 4490                "%" PRIu64 ": REMOVEXATTR %s/%" PRIu64
 4491                " (%s) "
 4492                "resolution failed",
 4493                state->finh->unique, uuid_utoa(state->resolve.gfid),
 4494                state->finh->nodeid, state->name);
 4495 
 4496         /* facilitate retry from VFS */
 4497         if (state->resolve.op_errno == ENOENT)
 4498             state->resolve.op_errno = ESTALE;
 4499 
 4500         send_fuse_err(state->this, state->finh, state->resolve.op_errno);
 4501         free_fuse_state(state);
 4502         return;
 4503     }
 4504 
 4505 #ifdef GF_TEST_FFOP
 4506     state->fd = fd_lookup(state->loc.inode, state->finh->pid);
 4507 #endif /* GF_TEST_FFOP */
 4508 
 4509     if (state->fd) {
 4510         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 4511                "%" PRIu64 ": REMOVEXATTR %p/%" PRIu64 " (%s)",
 4512                state->finh->unique, state->fd, state->finh->nodeid,
 4513                state->name);
 4514 
 4515         FUSE_FOP(state, fuse_removexattr_cbk, GF_FOP_FREMOVEXATTR, fremovexattr,
 4516                  state->fd, state->name, state->xdata);
 4517     } else {
 4518         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 4519                "%" PRIu64 ": REMOVEXATTR %s/%" PRIu64 " (%s)",
 4520                state->finh->unique, state->loc.path, state->finh->nodeid,
 4521                state->name);
 4522 
 4523         FUSE_FOP(state, fuse_removexattr_cbk, GF_FOP_REMOVEXATTR, removexattr,
 4524                  &state->loc, state->name, state->xdata);
 4525     }
 4526 }
 4527 
 4528 static void
 4529 fuse_removexattr(xlator_t *this, fuse_in_header_t *finh, void *msg,
 4530                  struct iobuf *iobuf)
 4531 {
 4532     char *name = msg;
 4533 
 4534     fuse_state_t *state = NULL;
 4535     fuse_private_t *priv = NULL;
 4536     int32_t ret = -1;
 4537     char *newkey = NULL;
 4538 
 4539     if (!strcmp(GFID_XATTR_KEY, name) || !strcmp(GF_XATTR_VOL_ID_KEY, name)) {
 4540         send_fuse_err(this, finh, EPERM);
 4541         GF_FREE(finh);
 4542         return;
 4543     }
 4544 
 4545     priv = this->private;
 4546 
 4547     GET_STATE(this, finh, state);
 4548 
 4549     fuse_resolve_inode_init(state, &state->resolve, finh->nodeid);
 4550 
 4551     ret = fuse_flip_xattr_ns(priv, name, &newkey);
 4552     if (ret) {
 4553         send_fuse_err(this, finh, ENOMEM);
 4554         free_fuse_state(state);
 4555         return;
 4556     }
 4557 
 4558     state->name = newkey;
 4559 
 4560     fuse_resolve_and_resume(state, fuse_removexattr_resume);
 4561     return;
 4562 }
 4563 
 4564 static int gf_fuse_lk_enosys_log;
 4565 
 4566 static int
 4567 fuse_getlk_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 4568                int32_t op_ret, int32_t op_errno, struct gf_flock *lock,
 4569                dict_t *xdata)
 4570 {
 4571     fuse_state_t *state = NULL;
 4572 
 4573     state = frame->root->state;
 4574     struct fuse_lk_out flo = {
 4575         {
 4576             0,
 4577         },
 4578     };
 4579 
 4580     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 4581 
 4582     if (op_ret == 0) {
 4583         gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": ERR => 0",
 4584                frame->root->unique);
 4585         flo.lk.type = lock->l_type;
 4586         flo.lk.pid = lock->l_pid;
 4587         if (lock->l_type == F_UNLCK)
 4588             flo.lk.start = flo.lk.end = 0;
 4589         else {
 4590             flo.lk.start = lock->l_start;
 4591             flo.lk.end = lock->l_len ? (lock->l_start + lock->l_len - 1)
 4592                                      : OFFSET_MAX;
 4593         }
 4594         send_fuse_obj(this, state->finh, &flo);
 4595     } else {
 4596         if (op_errno == ENOSYS) {
 4597             gf_fuse_lk_enosys_log++;
 4598             if (!(gf_fuse_lk_enosys_log % GF_UNIVERSAL_ANSWER)) {
 4599                 gf_log("glusterfs-fuse", GF_LOG_ERROR,
 4600                        "GETLK not supported. loading "
 4601                        "'features/posix-locks' on server side "
 4602                        "will add GETLK support.");
 4603             }
 4604         } else {
 4605             gf_log("glusterfs-fuse", GF_LOG_WARNING,
 4606                    "%" PRIu64 ": ERR => -1 (%s)", frame->root->unique,
 4607                    strerror(op_errno));
 4608         }
 4609         send_fuse_err(this, state->finh, op_errno);
 4610     }
 4611 
 4612     free_fuse_state(state);
 4613     STACK_DESTROY(frame->root);
 4614 
 4615     return 0;
 4616 }
 4617 
 4618 void
 4619 fuse_getlk_resume(fuse_state_t *state)
 4620 {
 4621     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": GETLK %p",
 4622            state->finh->unique, state->fd);
 4623 
 4624     FUSE_FOP(state, fuse_getlk_cbk, GF_FOP_LK, lk, state->fd, F_GETLK,
 4625              &state->lk_lock, state->xdata);
 4626 }
 4627 
 4628 static void
 4629 fuse_getlk(xlator_t *this, fuse_in_header_t *finh, void *msg,
 4630            struct iobuf *iobuf)
 4631 {
 4632     struct fuse_lk_in *fli = msg;
 4633 
 4634     fuse_state_t *state = NULL;
 4635     fd_t *fd = NULL;
 4636 
 4637     fd = FH_TO_FD(fli->fh);
 4638     GET_STATE(this, finh, state);
 4639     state->fd = fd;
 4640 
 4641     fuse_resolve_fd_init(state, &state->resolve, fd);
 4642 
 4643     convert_fuse_file_lock(&fli->lk, &state->lk_lock, fli->owner);
 4644 
 4645     state->lk_owner = fli->owner;
 4646 
 4647     fuse_resolve_and_resume(state, fuse_getlk_resume);
 4648 
 4649     return;
 4650 }
 4651 
 4652 static int
 4653 fuse_setlk_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
 4654                int32_t op_ret, int32_t op_errno, struct gf_flock *lock,
 4655                dict_t *xdata)
 4656 {
 4657     uint32_t op = 0;
 4658     fuse_state_t *state = NULL;
 4659     int ret = 0;
 4660 
 4661     ret = fuse_interrupt_finish_fop(frame, this, _gf_false, (void **)&state);
 4662     if (state) {
 4663         GF_FREE(state->name);
 4664         dict_unref(state->xdata);
 4665         GF_FREE(state);
 4666     }
 4667     if (ret) {
 4668         return 0;
 4669     }
 4670 
 4671     state = frame->root->state;
 4672     op = state->finh->opcode;
 4673 
 4674     fuse_log_eh_fop(this, state, frame, op_ret, op_errno);
 4675 
 4676     if (op_ret == 0) {
 4677         gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": ERR => 0",
 4678                frame->root->unique);
 4679         fd_lk_insert_and_merge(state->fd,
 4680                                (op == FUSE_SETLK) ? F_SETLK : F_SETLKW,
 4681                                &state->lk_lock);
 4682 
 4683         send_fuse_err(this, state->finh, 0);
 4684     } else {
 4685         if (op_errno == ENOSYS) {
 4686             gf_fuse_lk_enosys_log++;
 4687             if (!(gf_fuse_lk_enosys_log % GF_UNIVERSAL_ANSWER)) {
 4688                 gf_log("glusterfs-fuse", GF_LOG_ERROR,
 4689                        "SETLK not supported. loading "
 4690                        "'features/posix-locks' on server side "
 4691                        "will add SETLK support.");
 4692             }
 4693         } else if (op_errno == EAGAIN) {
 4694             gf_log("glusterfs-fuse", GF_LOG_DEBUG,
 4695                    "Returning EAGAIN Flock: "
 4696                    "start=%llu, len=%llu, pid=%llu, lk-owner=%s",
 4697                    (unsigned long long)state->lk_lock.l_start,
 4698                    (unsigned long long)state->lk_lock.l_len,
 4699                    (unsigned long long)state->lk_lock.l_pid,
 4700                    lkowner_utoa(&frame->root->lk_owner));
 4701         } else {
 4702             gf_log("glusterfs-fuse", GF_LOG_WARNING,
 4703                    "%" PRIu64 ": ERR => -1 (%s)", frame->root->unique,
 4704                    strerror(op_errno));
 4705         }
 4706 
 4707         send_fuse_err(this, state->finh, op_errno);
 4708     }
 4709 
 4710     free_fuse_state(state);
 4711     STACK_DESTROY(frame->root);
 4712 
 4713     return 0;
 4714 }
 4715 
 4716 static int
 4717 fuse_setlk_interrupt_handler_cbk(call_frame_t *frame, void *cookie,
 4718                                  xlator_t *this, int32_t op_ret,
 4719                                  int32_t op_errno, dict_t *dict, dict_t *xdata)
 4720 {
 4721     fuse_interrupt_state_t intstat = INTERRUPT_NONE;
 4722     fuse_interrupt_record_t *fir;
 4723     fuse_state_t *state = NULL;
 4724     int ret = 0;
 4725 
 4726     ret = dict_get_bin(xdata, "fuse-interrupt-record", (void **)&fir);
 4727     if (ret < 0) {
 4728         gf_log("glusterfs-fuse", GF_LOG_ERROR, "interrupt record not found");
 4729 
 4730         goto out;
 4731     }
 4732 
 4733     intstat = op_ret >= 0 ? INTERRUPT_HANDLED : INTERRUPT_SQUELCHED;
 4734 
 4735     fuse_interrupt_finish_interrupt(this, fir, intstat, _gf_false,
 4736                                     (void **)&state);
 4737     if (state) {
 4738         GF_FREE(state->name);
 4739         dict_unref(state->xdata);
 4740         GF_FREE(state);
 4741     }
 4742 
 4743 out:
 4744     STACK_DESTROY(frame->root);
 4745 
 4746     return 0;
 4747 }
 4748 
 4749 static void
 4750 fuse_setlk_interrupt_handler(xlator_t *this, fuse_interrupt_record_t *fir)
 4751 {
 4752     fuse_state_t *state = NULL;
 4753     call_frame_t *frame = NULL;
 4754     char *xattr_name = NULL;
 4755     int ret = 0;
 4756 
 4757     gf_log("glusterfs-fuse", GF_LOG_DEBUG,
 4758            "SETLK%s unique %" PRIu64 ": interrupt handler triggered",
 4759            fir->fuse_in_header.opcode == FUSE_SETLK ? "" : "W",
 4760            fir->fuse_in_header.unique);
 4761 
 4762     state = fir->data;
 4763 
 4764     ret = gf_asprintf(
 4765         &xattr_name, GF_XATTR_CLRLK_CMD ".tposix.kblocked.%hd,%jd-%jd",
 4766         state->lk_lock.l_whence, state->lk_lock.l_start, state->lk_lock.l_len);
 4767     if (ret == -1) {
 4768         xattr_name = NULL;
 4769         goto err;
 4770     }
 4771 
 4772     frame = get_call_frame_for_req(state);
 4773     if (!frame) {
 4774         goto err;
 4775     }
 4776     frame->root->state = state;
 4777     frame->root->op = GF_FOP_GETXATTR;
 4778     frame->op = GF_FOP_GETXATTR;
 4779     state->name = xattr_name;
 4780 
 4781     STACK_WIND(frame, fuse_setlk_interrupt_handler_cbk, state->active_subvol,
 4782                state->active_subvol->fops->fgetxattr, state->fd, xattr_name,
 4783                state->xdata);
 4784 
 4785     return;
 4786 
 4787 err:
 4788     GF_FREE(xattr_name);
 4789     fuse_interrupt_finish_interrupt(this, fir, INTERRUPT_SQUELCHED, _gf_false,
 4790                                     (void **)&state);
 4791     if (state) {
 4792         dict_unref(state->xdata);
 4793         GF_FREE(state);
 4794     }
 4795 }
 4796 
 4797 void
 4798 fuse_setlk_resume(fuse_state_t *state)
 4799 {
 4800     fuse_interrupt_record_t *fir = NULL;
 4801     fuse_state_t *state_clone = NULL;
 4802 
 4803     fir = fuse_interrupt_record_new(state->finh, fuse_setlk_interrupt_handler);
 4804     state_clone = gf_memdup(state, sizeof(*state));
 4805     if (state_clone) {
 4806         /*
 4807          * Calling this allocator with fir casted to (char *) seems like
 4808          * an abuse of this API, but in fact the API is stupid to assume
 4809          * a (char *) argument (in the funcion it's casted to (void *)
 4810          * anyway).
 4811          */
 4812         state_clone->xdata = dict_for_key_value(
 4813             "fuse-interrupt-record", (char *)fir, sizeof(*fir), _gf_true);
 4814     }
 4815     if (!fir || !state_clone || !state_clone->xdata) {
 4816         if (fir) {
 4817             GF_FREE(fir);
 4818         }
 4819         if (state_clone) {
 4820             GF_FREE(state_clone);
 4821         }
 4822         send_fuse_err(state->this, state->finh, ENOMEM);
 4823 
 4824         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 4825                "SETLK%s unique %" PRIu64
 4826                ":"
 4827                " interrupt record allocation failed",
 4828                state->finh->opcode == FUSE_SETLK ? "" : "W",
 4829                state->finh->unique);
 4830         free_fuse_state(state);
 4831 
 4832         return;
 4833     }
 4834     state_clone->name = NULL;
 4835     fir->data = state_clone;
 4836     fuse_interrupt_record_insert(state->this, fir);
 4837 
 4838     gf_log("glusterfs-fuse", GF_LOG_TRACE, "%" PRIu64 ": SETLK%s %p",
 4839            state->finh->unique, state->finh->opcode == FUSE_SETLK ? "" : "W",
 4840            state->fd);
 4841 
 4842     FUSE_FOP(state, fuse_setlk_cbk, GF_FOP_LK, lk, state->fd,
 4843              state->finh->opcode == FUSE_SETLK ? F_SETLK : F_SETLKW,
 4844              &state->lk_lock, state->xdata);
 4845 }
 4846 
 4847 static void
 4848 fuse_setlk(xlator_t *this, fuse_in_header_t *finh, void *msg,
 4849            struct iobuf *iobuf)
 4850 {
 4851     struct fuse_lk_in *fli = msg;
 4852 
 4853     fuse_state_t *state = NULL;
 4854     fd_t *fd = NULL;
 4855 
 4856     fd = FH_TO_FD(fli->fh);
 4857     GET_STATE(this, finh, state);
 4858     state->finh = finh;
 4859     state->fd = fd;
 4860 
 4861     fuse_resolve_fd_init(state, &state->resolve, fd);
 4862 
 4863     convert_fuse_file_lock(&fli->lk, &state->lk_lock, fli->owner);
 4864 
 4865     state->lk_owner = fli->owner;
 4866 
 4867     fuse_resolve_and_resume(state, fuse_setlk_resume);
 4868 
 4869     return;
 4870 }
 4871 
 4872 #if FUSE_KERNEL_MINOR_VERSION >= 11
 4873 static void *
 4874 notify_kernel_loop(void *data)
 4875 {
 4876     uint32_t len = 0;
 4877     ssize_t rv = 0;
 4878     xlator_t *this = NULL;
 4879     fuse_private_t *priv = NULL;
 4880     fuse_invalidate_node_t *node = NULL;
 4881     fuse_invalidate_node_t *tmp = NULL;
 4882     struct fuse_out_header *pfoh = NULL;
 4883     struct iovec iov_out = {
 4884         0,
 4885     };
 4886 
 4887     this = data;
 4888     priv = this->private;
 4889 
 4890     for (;;) {
 4891         pthread_mutex_lock(&priv->invalidate_mutex);
 4892         {
 4893             while (list_empty(&priv->invalidate_list))
 4894                 pthread_cond_wait(&priv->invalidate_cond,
 4895                                   &priv->invalidate_mutex);
 4896 
 4897             node = list_entry(priv->invalidate_list.next,
 4898                               fuse_invalidate_node_t, next);
 4899 
 4900             list_del_init(&node->next);
 4901         }
 4902         pthread_mutex_unlock(&priv->invalidate_mutex);
 4903 
 4904         pfoh = (struct fuse_out_header *)node->inval_buf;
 4905         memcpy(&len, &pfoh->len, sizeof(len));
 4906         /*
 4907          * a simple
 4908          *         len = pfoh->len;
 4909          * works on x86, but takes a multiple insn cycle hit
 4910          * when pfoh->len is not correctly aligned, possibly
 4911          * even stalling the insn pipeline.
 4912          * Other architectures will not be so forgiving. If
 4913          * we're lucky the memcpy will be inlined by the
 4914          * compiler, and might be as fast or faster without
 4915          * the risk of stalling the insn pipeline.
 4916          */
 4917 
 4918         iov_out.iov_base = node->inval_buf;
 4919         iov_out.iov_len = len;
 4920         rv = sys_writev(priv->fd, &iov_out, 1);
 4921         check_and_dump_fuse_W(priv, &iov_out, 1, rv, node->errnomask);
 4922 
 4923         GF_FREE(node);
 4924 
 4925         if (rv == -1 && errno == EBADF)
 4926             break;
 4927 
 4928         if (rv != len && !(rv == -1 && errno == ENOENT)) {
 4929             gf_log("glusterfs-fuse", GF_LOG_INFO, "len: %u, rv: %zd, errno: %d",
 4930                    len, rv, errno);
 4931         }
 4932     }
 4933 
 4934     gf_log("glusterfs-fuse", GF_LOG_ERROR, "kernel notifier loop terminated");
 4935 
 4936     pthread_mutex_lock(&priv->invalidate_mutex);
 4937     {
 4938         priv->reverse_fuse_thread_started = _gf_false;
 4939         list_for_each_entry_safe(node, tmp, &priv->invalidate_list, next)
 4940         {
 4941             list_del_init(&node->next);
 4942             GF_FREE(node);
 4943         }
 4944     }
 4945     pthread_mutex_unlock(&priv->invalidate_mutex);
 4946 
 4947     return NULL;
 4948 }
 4949 #endif
 4950 
 4951 static void *
 4952 timed_response_loop(void *data)
 4953 {
 4954     ssize_t rv = 0;
 4955     size_t len = 0;
 4956     xlator_t *this = NULL;
 4957     fuse_private_t *priv = NULL;
 4958     fuse_timed_message_t *dmsg = NULL;
 4959     fuse_timed_message_t *tmp = NULL;
 4960     struct timespec now = {
 4961         0,
 4962     };
 4963     struct timespec delta = {
 4964         0,
 4965     };
 4966     struct iovec iovs[2] = {
 4967         {
 4968             0,
 4969         },
 4970     };
 4971 
 4972     this = data;
 4973     priv = this->private;
 4974 
 4975     for (;;) {
 4976         pthread_mutex_lock(&priv->timed_mutex);
 4977         {
 4978             while (list_empty(&priv->timed_list)) {
 4979                 pthread_cond_wait(&priv->timed_cond, &priv->timed_mutex);
 4980             }
 4981 
 4982             dmsg = list_entry(priv->timed_list.next, fuse_timed_message_t,
 4983                               next);
 4984             list_for_each_entry(tmp, &priv->timed_list, next)
 4985             {
 4986                 if (timespec_cmp(&tmp->scheduled_ts, &dmsg->scheduled_ts) < 0) {
 4987                     dmsg = tmp;
 4988                 }
 4989             }
 4990 
 4991             list_del_init(&dmsg->next);
 4992         }
 4993         pthread_mutex_unlock(&priv->timed_mutex);
 4994 
 4995         timespec_now(&now);
 4996         if (timespec_cmp(&now, &dmsg->scheduled_ts) < 0) {
 4997             timespec_sub(&now, &dmsg->scheduled_ts, &delta);
 4998             nanosleep(&delta, NULL);
 4999         }
 5000 
 5001         gf_log("glusterfs-fuse", GF_LOG_TRACE,
 5002                "sending timed "
 5003                "message of unique %" PRIu64,
 5004                dmsg->fuse_out_header.unique);
 5005 
 5006         len = dmsg->fuse_out_header.len;
 5007         iovs[0] = (struct iovec){&dmsg->fuse_out_header,
 5008                                  sizeof(struct fuse_out_header)};
 5009         iovs[1] = (struct iovec){dmsg->fuse_message_body,
 5010                                  len - sizeof(struct fuse_out_header)};
 5011         rv = sys_writev(priv->fd, iovs, 2);
 5012         check_and_dump_fuse_W(priv, iovs, 2, rv, dmsg->errnomask);
 5013 
 5014         fuse_timed_message_free(dmsg);
 5015 
 5016         if (rv == -1 && errno == EBADF) {
 5017             break;
 5018         }
 5019 
 5020         if (rv != len && !(rv == -1 && errno == ENOENT)) {
 5021             gf_log("glusterfs-fuse", GF_LOG_INFO,
 5022                    "len: %zu, rv: %zd, errno: %d", len, rv, errno);
 5023         }
 5024     }
 5025 
 5026     gf_log("glusterfs-fuse", GF_LOG_ERROR, "timed response loop terminated");
 5027 
 5028     pthread_mutex_lock(&priv->timed_mutex);
 5029     {
 5030         priv->timed_response_fuse_thread_started = _gf_false;
 5031         list_for_each_entry_safe(dmsg, tmp, &priv->timed_list, next)
 5032         {
 5033             list_del_init(&dmsg->next);
 5034             fuse_timed_message_free(dmsg);
 5035         }
 5036     }
 5037     pthread_mutex_unlock(&priv->timed_mutex);
 5038 
 5039     return NULL;
 5040 }
 5041 
 5042 static void
 5043 fuse_init(xlator_t *this, fuse_in_header_t *finh, void *msg,
 5044           struct iobuf *iobuf)
 5045 {
 5046     struct fuse_init_in *fini = msg;
 5047     struct fuse_init_out fino = {
 5048         0,
 5049     };
 5050     fuse_private_t *priv = NULL;
 5051     size_t size = 0;
 5052     int ret = 0;
 5053 #if FUSE_KERNEL_MINOR_VERSION >= 9
 5054     pthread_t messenger;
 5055 #endif
 5056     pthread_t delayer;
 5057 
 5058     priv = this->private;
 5059 
 5060     if (priv->init_recvd) {
 5061         gf_log("glusterfs-fuse", GF_LOG_ERROR, "got INIT after first message");
 5062 
 5063         sys_close(priv->fd);
 5064         goto out;
 5065     }
 5066 
 5067     priv->init_recvd = 1;
 5068 
 5069     if (fini->major != FUSE_KERNEL_VERSION) {
 5070         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 5071                "unsupported FUSE protocol version %d.%d", fini->major,
 5072                fini->minor);
 5073 
 5074         sys_close(priv->fd);
 5075         goto out;
 5076     }
 5077     priv->proto_minor = fini->minor;
 5078 
 5079     fino.major = FUSE_KERNEL_VERSION;
 5080     fino.minor = FUSE_KERNEL_MINOR_VERSION;
 5081     fino.max_readahead = 1 << 17;
 5082     fino.max_write = 1 << 17;
 5083     fino.flags = FUSE_ASYNC_READ | FUSE_POSIX_LOCKS;
 5084 #if FUSE_KERNEL_MINOR_VERSION >= 17
 5085     if (fini->minor >= 17)
 5086         fino.flags |= FUSE_FLOCK_LOCKS;
 5087 #endif
 5088 #if FUSE_KERNEL_MINOR_VERSION >= 12
 5089     if (fini->minor >= 12) {
 5090         /* let fuse leave the umask processing to us, so that it does not
 5091          * break extended POSIX ACL defaults on server */
 5092         fino.flags |= FUSE_DONT_MASK;
 5093     }
 5094 #endif
 5095 #if FUSE_KERNEL_MINOR_VERSION >= 9
 5096     if (fini->minor >= 6 /* fuse_init_in has flags */ &&
 5097         fini->flags & FUSE_BIG_WRITES) {
 5098         /* no need for direct I/O mode by default if big writes are supported */
 5099         if (priv->direct_io_mode == 2)
 5100             priv->direct_io_mode = 0;
 5101         fino.flags |= FUSE_BIG_WRITES;
 5102     }
 5103 
 5104     /* Start the thread processing timed responses */
 5105     ret = gf_thread_create(&delayer, NULL, timed_response_loop, this,
 5106                            "fusedlyd");
 5107     if (ret != 0) {
 5108         gf_log("glusterfs-fuse", GF_LOG_ERROR,
 5109                "failed to start timed response thread (%s)", strerror(errno));
 5110 
 5111         sys_close(priv->fd);
 5112         goto out;
 5113     }
 5114     priv->timed_response_fuse_thread_started = _gf_true;
 5115 
 5116     /* Used for 'reverse invalidation of inode' */
 5117     if (fini->minor >= 12) {
 5118         ret = gf_thread_create(&messenger, NULL, notify_kernel_loop, this,
 5119                                "fusenoti");
 5120         if (ret != 0) {
 5121             gf_log("glusterfs-fuse", GF_LOG_ERROR,
 5122                    "failed to start messenger daemon (%s)", strerror(errno));
 5123 
 5124             sys_close(priv->fd);
 5125             goto out;
 5126         }
 5127         priv->reverse_fuse_thread_started = _gf_true;
 5128     } else {
 5129         /*
 5130          * FUSE minor < 12 does not implement invalidate notifications.
 5131          * This mechanism is required for fopen-keep-cache to operate
 5132          * correctly. Disable and warn the user.
 5133          */
 5134         if (priv->fopen_keep_cache) {
 5135             gf_log("glusterfs-fuse", GF_LOG_WARNING,
 5136                    "FUSE version "
 5137                    "%d.%d does not support inval notifications. "
 5138                    "fopen-keep-cache disabled.",
 5139                    fini->major, fini->minor);
 5140             priv->fopen_keep_cache = 0;
 5141         }
 5142     }
 5143 
 5144     if (fini->minor >= 13) {
 5145         fino.max_background = priv->background_qlen;
 5146         fino.congestion_threshold = priv->congestion_threshold;
 5147     }
 5148     if (fini->minor < 9)
 5149         *priv->msg0_len_p = sizeof(*finh) + FUSE_COMPAT_WRITE_IN_SIZE;
 5150 
 5151     if (priv->use_readdirp) {
 5152         if (fini->flags & FUSE_DO_READDIRPLUS)
 5153             fino.flags |= FUSE_DO_READDIRPLUS;
 5154     }
 5155 #endif
 5156     if (priv->fopen_keep_cache == 2) {
 5157         /* If user did not explicitly set --fopen-keep-cache[=off],
 5158            then check if kernel support FUSE_AUTO_INVAL_DATA and ...
 5159         */
 5160 
 5161         priv->fopen_keep_cache = 1;
 5162 
 5163 #if FUSE_KERNEL_MINOR_VERSION >= 20
 5164         if (fini->flags & FUSE_AUTO_INVAL_DATA) {
 5165             /* ... enable fopen_keep_cache mode if supported.
 5166              */
 5167             gf_log("glusterfs-fuse", GF_LOG_DEBUG,
 5168                    "Detected "
 5169                    "support for FUSE_AUTO_INVAL_DATA. Enabling "
 5170                    "fopen_keep_cache automatically.");
 5171 
 5172             if (priv->fuse_auto_inval)
 5173                 fino.flags |= FUSE_AUTO_INVAL_DATA;
 5174         } else
 5175 #endif
 5176         {
 5177             if (priv->fuse_auto_inval) {
 5178                 gf_log("glusterfs-fuse", GF_LOG_DEBUG,
 5179                        "No support for FUSE_AUTO_INVAL_DATA. Disabling "
 5180                        "fopen_keep_cache.");
 5181                 /* ... else disable. */
 5182                 priv->fopen_keep_cache = 0;
 5183             }
 5184         }
 5185     } else if (priv->fopen_keep_cache == 1) {
 5186         /* If user explicitly set --fopen-keep-cache[=on],
 5187            then enable FUSE_AUTO_INVAL_DATA if possible.
 5188         */
 5189 #if FUSE_KERNEL_MINOR_VERSION >= 20
 5190         if (priv->fuse_auto_inval && (fini->flags & FUSE_AUTO_INVAL_DATA)) {
 5191             gf_log("glusterfs-fuse", GF_LOG_DEBUG,
 5192                    "fopen_keep_cache "
 5193                    "is explicitly set. Enabling FUSE_AUTO_INVAL_DATA");
 5194             fino.flags |= FUSE_AUTO_INVAL_DATA;
 5195         } else
 5196 #endif
 5197         {
 5198             gf_log("glusterfs-fuse", GF_LOG_WARNING,
 5199                    "fopen_keep_cache "
 5200                    "is explicitly set. Support for "
 5201                    "FUSE_AUTO_INVAL_DATA is missing");
 5202         }
 5203     }
 5204 
 5205 #if FUSE_KERNEL_MINOR_VERSION >= 22
 5206     if (fini->flags & FUSE_ASYNC_DIO)
 5207         fino.flags |= FUSE_ASYNC_DIO;
 5208 #endif
 5209 
 5210     size =<