"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.2/xlators/mount/fuse/src/fuse-resolve.c" (16 Sep 2020, 18281 Bytes) of package /linux/misc/glusterfs-8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fuse-resolve.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2    Copyright (c) 2010-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 #include "fuse-bridge.h"
   11 
   12 static int
   13 fuse_resolve_all(fuse_state_t *state);
   14 
   15 int
   16 fuse_resolve_continue(fuse_state_t *state);
   17 int
   18 fuse_resolve_entry_simple(fuse_state_t *state);
   19 int
   20 fuse_resolve_inode_simple(fuse_state_t *state);
   21 int
   22 fuse_migrate_fd(xlator_t *this, fd_t *fd, xlator_t *old_subvol,
   23                 xlator_t *new_subvol);
   24 
   25 fuse_fd_ctx_t *
   26 fuse_fd_ctx_get(xlator_t *this, fd_t *fd);
   27 
   28 static int
   29 fuse_resolve_loc_touchup(fuse_state_t *state)
   30 {
   31     fuse_resolve_t *resolve = NULL;
   32     loc_t *loc = NULL;
   33 
   34     resolve = state->resolve_now;
   35     loc = state->loc_now;
   36 
   37     loc_touchup(loc, resolve->bname);
   38     return 0;
   39 }
   40 
   41 int
   42 fuse_resolve_entry_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
   43                        int op_ret, int op_errno, inode_t *inode,
   44                        struct iatt *buf, dict_t *xattr, struct iatt *postparent)
   45 {
   46     fuse_state_t *state = NULL;
   47     fuse_resolve_t *resolve = NULL;
   48     inode_t *link_inode = NULL;
   49     loc_t *resolve_loc = NULL;
   50     uint64_t ctx_value = LOOKUP_NOT_NEEDED;
   51 
   52     state = frame->root->state;
   53     resolve = state->resolve_now;
   54     resolve_loc = &resolve->resolve_loc;
   55 
   56     STACK_DESTROY(frame->root);
   57 
   58     if (op_ret == -1) {
   59         gf_log(this->name, (op_errno == ENOENT) ? GF_LOG_DEBUG : GF_LOG_WARNING,
   60                "%s/%s: failed to resolve (%s)", uuid_utoa(resolve_loc->pargfid),
   61                resolve_loc->name, strerror(op_errno));
   62         resolve->op_ret = -1;
   63         resolve->op_errno = op_errno;
   64         goto out;
   65     }
   66 
   67     link_inode = inode_link(inode, resolve_loc->parent, resolve_loc->name, buf);
   68     if (link_inode == inode)
   69         inode_ctx_set(link_inode, this, &ctx_value);
   70     state->loc_now->inode = link_inode;
   71 
   72 out:
   73     loc_wipe(resolve_loc);
   74 
   75     fuse_resolve_continue(state);
   76     return 0;
   77 }
   78 
   79 int
   80 fuse_resolve_entry(fuse_state_t *state)
   81 {
   82     fuse_resolve_t *resolve = NULL;
   83     loc_t *resolve_loc = NULL;
   84 
   85     resolve = state->resolve_now;
   86     resolve_loc = &resolve->resolve_loc;
   87 
   88     resolve_loc->parent = inode_ref(state->loc_now->parent);
   89     gf_uuid_copy(resolve_loc->pargfid, state->loc_now->pargfid);
   90     resolve_loc->name = resolve->bname;
   91 
   92     resolve_loc->inode = inode_grep(state->itable, resolve->parhint,
   93                                     resolve->bname);
   94     if (!resolve_loc->inode) {
   95         resolve_loc->inode = inode_new(state->itable);
   96     }
   97     inode_path(resolve_loc->parent, resolve_loc->name,
   98                (char **)&resolve_loc->path);
   99 
  100     FUSE_FOP(state, fuse_resolve_entry_cbk, GF_FOP_LOOKUP, lookup, resolve_loc,
  101              NULL);
  102 
  103     return 0;
  104 }
  105 
  106 int
  107 fuse_resolve_gfid_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
  108                       int op_ret, int op_errno, inode_t *inode,
  109                       struct iatt *buf, dict_t *xattr, struct iatt *postparent)
  110 {
  111     fuse_state_t *state = NULL;
  112     fuse_resolve_t *resolve = NULL;
  113     inode_t *link_inode = NULL;
  114     loc_t *loc_now = NULL;
  115     inode_t *tmp_inode = NULL;
  116     uint64_t ctx_value = LOOKUP_NOT_NEEDED;
  117 
  118     state = frame->root->state;
  119     resolve = state->resolve_now;
  120     loc_now = state->loc_now;
  121 
  122     STACK_DESTROY(frame->root);
  123 
  124     if (op_ret == -1) {
  125         gf_log(this->name, (op_errno == ENOENT) ? GF_LOG_DEBUG : GF_LOG_WARNING,
  126                "%s: failed to resolve (%s)",
  127                uuid_utoa(resolve->resolve_loc.gfid), strerror(op_errno));
  128         loc_wipe(&resolve->resolve_loc);
  129 
  130         /* resolve->op_ret can have 3 values: 0, -1, -2.
  131          * 0 : resolution was successful.
  132          * -1: parent inode could not be resolved.
  133          * -2: entry (inode corresponding to path) could not be resolved
  134          */
  135 
  136         if (gf_uuid_is_null(resolve->gfid)) {
  137             resolve->op_ret = -1;
  138         } else {
  139             resolve->op_ret = -2;
  140         }
  141 
  142         resolve->op_errno = op_errno;
  143         goto out;
  144     }
  145 
  146     link_inode = inode_link(inode, NULL, NULL, buf);
  147     if (link_inode == inode)
  148         inode_ctx_set(link_inode, this, &ctx_value);
  149 
  150     loc_wipe(&resolve->resolve_loc);
  151 
  152     if (!link_inode)
  153         goto out;
  154 
  155     if (!gf_uuid_is_null(resolve->gfid)) {
  156         loc_now->inode = link_inode;
  157         goto out;
  158     }
  159 
  160     loc_now->parent = link_inode;
  161     gf_uuid_copy(loc_now->pargfid, link_inode->gfid);
  162 
  163     tmp_inode = inode_grep(state->itable, link_inode, resolve->bname);
  164     if (tmp_inode && (!inode_needs_lookup(tmp_inode, THIS))) {
  165         loc_now->inode = tmp_inode;
  166         goto out;
  167     }
  168 
  169     inode_unref(tmp_inode);
  170     fuse_resolve_entry(state);
  171 
  172     return 0;
  173 out:
  174     fuse_resolve_continue(state);
  175     return 0;
  176 }
  177 
  178 int
  179 fuse_resolve_gfid(fuse_state_t *state)
  180 {
  181     fuse_resolve_t *resolve = NULL;
  182     loc_t *resolve_loc = NULL;
  183     int ret = 0;
  184 
  185     resolve = state->resolve_now;
  186     resolve_loc = &resolve->resolve_loc;
  187 
  188     if (!gf_uuid_is_null(resolve->pargfid)) {
  189         gf_uuid_copy(resolve_loc->gfid, resolve->pargfid);
  190     } else if (!gf_uuid_is_null(resolve->gfid)) {
  191         gf_uuid_copy(resolve_loc->gfid, resolve->gfid);
  192     }
  193 
  194     /* inode may already exist in case we are looking up an inode which was
  195        linked through readdirplus */
  196     resolve_loc->inode = inode_find(state->itable, resolve_loc->gfid);
  197     if (!resolve_loc->inode)
  198         resolve_loc->inode = inode_new(state->itable);
  199     ret = loc_path(resolve_loc, NULL);
  200 
  201     if (ret <= 0) {
  202         gf_log(THIS->name, GF_LOG_WARNING,
  203                "failed to get the path for inode %s", uuid_utoa(resolve->gfid));
  204     }
  205 
  206     FUSE_FOP(state, fuse_resolve_gfid_cbk, GF_FOP_LOOKUP, lookup, resolve_loc,
  207              NULL);
  208 
  209     return 0;
  210 }
  211 
  212 /*
  213  * Return value:
  214  * 0 - resolved parent and entry (as necessary)
  215  * -1 - resolved parent but not entry (though necessary)
  216  * 1 - resolved neither parent nor entry
  217  */
  218 
  219 int
  220 fuse_resolve_parent_simple(fuse_state_t *state)
  221 {
  222     fuse_resolve_t *resolve = NULL;
  223     loc_t *loc = NULL;
  224     inode_t *parent = NULL;
  225     inode_t *inode = NULL;
  226     xlator_t *this = NULL;
  227 
  228     resolve = state->resolve_now;
  229     loc = state->loc_now;
  230     this = state->this;
  231 
  232     loc->name = resolve->bname;
  233 
  234     parent = resolve->parhint;
  235     if (parent->table == state->itable) {
  236         if (inode_needs_lookup(parent, THIS))
  237             return 1;
  238 
  239         /* no graph switches since */
  240         loc->parent = inode_ref(parent);
  241         gf_uuid_copy(loc->pargfid, parent->gfid);
  242         loc->inode = inode_grep(state->itable, parent, loc->name);
  243 
  244         /* nodeid for root is 1 and we blindly take the latest graph's
  245          * table->root as the parhint and because of this there is
  246          * ambiguity whether the entry should have existed or not, and
  247          * we took the conservative approach of assuming entry should
  248          * have been there even though it need not have (bug #804592).
  249          */
  250 
  251         if (loc->inode && inode_needs_lookup(loc->inode, THIS)) {
  252             inode_unref(loc->inode);
  253             loc->inode = NULL;
  254             return -1;
  255         }
  256 
  257         if ((loc->inode == NULL) && __is_root_gfid(parent->gfid)) {
  258             /* non decisive result - entry missing */
  259             return -1;
  260         }
  261 
  262         /* decisive result - resolution success */
  263         return 0;
  264     }
  265 
  266     parent = inode_find(state->itable, resolve->pargfid);
  267     if (!parent) {
  268         /* non decisive result - parent missing */
  269         return 1;
  270     }
  271     if (inode_needs_lookup(parent, THIS)) {
  272         inode_unref(parent);
  273         return 1;
  274     }
  275 
  276     loc->parent = parent;
  277     gf_uuid_copy(loc->pargfid, resolve->pargfid);
  278 
  279     inode = inode_grep(state->itable, parent, loc->name);
  280     if (inode && !inode_needs_lookup(inode, this)) {
  281         loc->inode = inode;
  282         /* decisive result - resolution success */
  283         return 0;
  284     }
  285 
  286     /* non decisive result - entry missing */
  287     return -1;
  288 }
  289 
  290 int
  291 fuse_resolve_parent(fuse_state_t *state)
  292 {
  293     int ret = 0;
  294 
  295     ret = fuse_resolve_parent_simple(state);
  296     if (ret > 0) {
  297         fuse_resolve_gfid(state);
  298         return 0;
  299     }
  300 
  301     if (ret < 0) {
  302         fuse_resolve_entry(state);
  303         return 0;
  304     }
  305 
  306     fuse_resolve_continue(state);
  307 
  308     return 0;
  309 }
  310 
  311 int
  312 fuse_resolve_inode_simple(fuse_state_t *state)
  313 {
  314     fuse_resolve_t *resolve = NULL;
  315     loc_t *loc = NULL;
  316     inode_t *inode = NULL;
  317 
  318     resolve = state->resolve_now;
  319     loc = state->loc_now;
  320 
  321     inode = resolve->hint;
  322     if (inode->table == state->itable)
  323         inode_ref(inode);
  324     else
  325         inode = inode_find(state->itable, resolve->gfid);
  326 
  327     if (inode) {
  328         if (!inode_needs_lookup(inode, THIS))
  329             goto found;
  330         /* inode was linked through readdirplus */
  331         inode_unref(inode);
  332     }
  333 
  334     return 1;
  335 found:
  336     loc->inode = inode;
  337     return 0;
  338 }
  339 
  340 int
  341 fuse_resolve_inode(fuse_state_t *state)
  342 {
  343     int ret = 0;
  344 
  345     ret = fuse_resolve_inode_simple(state);
  346 
  347     if (ret > 0) {
  348         fuse_resolve_gfid(state);
  349         return 0;
  350     }
  351 
  352     fuse_resolve_continue(state);
  353 
  354     return 0;
  355 }
  356 
  357 int
  358 fuse_migrate_fd_task(void *data)
  359 {
  360     int ret = -1;
  361     fuse_state_t *state = NULL;
  362     fd_t *basefd = NULL, *oldfd = NULL;
  363     fuse_fd_ctx_t *basefd_ctx = NULL;
  364     xlator_t *old_subvol = NULL;
  365 
  366     state = data;
  367     if (state == NULL) {
  368         goto out;
  369     }
  370 
  371     basefd = state->fd;
  372 
  373     basefd_ctx = fuse_fd_ctx_get(state->this, basefd);
  374     if (!basefd_ctx)
  375         goto out;
  376 
  377     LOCK(&basefd->lock);
  378     {
  379         oldfd = basefd_ctx->activefd ? basefd_ctx->activefd : basefd;
  380         fd_ref(oldfd);
  381     }
  382     UNLOCK(&basefd->lock);
  383 
  384     old_subvol = oldfd->inode->table->xl;
  385 
  386     ret = fuse_migrate_fd(state->this, basefd, old_subvol,
  387                           state->active_subvol);
  388 
  389     LOCK(&basefd->lock);
  390     {
  391         if (ret < 0) {
  392             basefd_ctx->migration_failed = 1;
  393         } else {
  394             basefd_ctx->migration_failed = 0;
  395         }
  396     }
  397     UNLOCK(&basefd->lock);
  398 
  399     ret = 0;
  400 
  401 out:
  402     if (oldfd)
  403         fd_unref(oldfd);
  404 
  405     return ret;
  406 }
  407 
  408 static int
  409 fuse_migrate_fd_error(xlator_t *this, fd_t *fd)
  410 {
  411     fuse_fd_ctx_t *fdctx = NULL;
  412     char error = 0;
  413 
  414     fdctx = fuse_fd_ctx_get(this, fd);
  415     if (fdctx != NULL) {
  416         if (fdctx->migration_failed) {
  417             error = 1;
  418         }
  419     }
  420 
  421     return error;
  422 }
  423 
  424 #define FUSE_FD_GET_ACTIVE_FD(activefd, basefd)                                \
  425     do {                                                                       \
  426         LOCK(&basefd->lock);                                                   \
  427         {                                                                      \
  428             activefd = basefd_ctx->activefd ? basefd_ctx->activefd : basefd;   \
  429             if (activefd != basefd) {                                          \
  430                 fd_ref(activefd);                                              \
  431             }                                                                  \
  432         }                                                                      \
  433         UNLOCK(&basefd->lock);                                                 \
  434                                                                                \
  435         if (activefd == basefd) {                                              \
  436             fd_ref(activefd);                                                  \
  437         }                                                                      \
  438     } while (0);
  439 
  440 static int
  441 fuse_resolve_fd(fuse_state_t *state)
  442 {
  443     fuse_resolve_t *resolve = NULL;
  444     fd_t *basefd = NULL, *activefd = NULL;
  445     xlator_t *active_subvol = NULL, *this = NULL;
  446     int ret = 0;
  447     char fd_migration_error = 0;
  448     fuse_fd_ctx_t *basefd_ctx = NULL;
  449 
  450     resolve = state->resolve_now;
  451 
  452     this = state->this;
  453 
  454     basefd = resolve->fd;
  455     basefd_ctx = fuse_fd_ctx_get(this, basefd);
  456     if (basefd_ctx == NULL) {
  457         gf_log(state->this->name, GF_LOG_WARNING,
  458                "fdctx is NULL for basefd (ptr:%p inode-gfid:%s), "
  459                "resolver erroring out with errno EINVAL",
  460                basefd, uuid_utoa(basefd->inode->gfid));
  461         resolve->op_ret = -1;
  462         resolve->op_errno = EINVAL;
  463         goto resolve_continue;
  464     }
  465 
  466     FUSE_FD_GET_ACTIVE_FD(activefd, basefd);
  467 
  468     active_subvol = activefd->inode->table->xl;
  469 
  470     fd_migration_error = fuse_migrate_fd_error(state->this, basefd);
  471     if (fd_migration_error) {
  472         resolve->op_ret = -1;
  473         resolve->op_errno = EBADF;
  474     } else if (state->active_subvol != active_subvol) {
  475         ret = synctask_new(state->this->ctx->env, fuse_migrate_fd_task, NULL,
  476                            NULL, state);
  477 
  478         fd_migration_error = fuse_migrate_fd_error(state->this, basefd);
  479         fd_unref(activefd);
  480 
  481         FUSE_FD_GET_ACTIVE_FD(activefd, basefd);
  482         active_subvol = activefd->inode->table->xl;
  483 
  484         if ((ret == -1) || fd_migration_error ||
  485             (state->active_subvol != active_subvol)) {
  486             if (ret == -1) {
  487                 gf_log(state->this->name, GF_LOG_WARNING,
  488                        "starting sync-task to migrate "
  489                        "basefd (ptr:%p inode-gfid:%s) failed "
  490                        "(old-subvolume:%s-%d "
  491                        "new-subvolume:%s-%d)",
  492                        basefd, uuid_utoa(basefd->inode->gfid),
  493                        active_subvol->name, active_subvol->graph->id,
  494                        state->active_subvol->name,
  495                        state->active_subvol->graph->id);
  496             } else {
  497                 gf_log(state->this->name, GF_LOG_WARNING,
  498                        "fd migration of basefd "
  499                        "(ptr:%p inode-gfid:%s) failed "
  500                        "(old-subvolume:%s-%d "
  501                        "new-subvolume:%s-%d)",
  502                        basefd, uuid_utoa(basefd->inode->gfid),
  503                        active_subvol->name, active_subvol->graph->id,
  504                        state->active_subvol->name,
  505                        state->active_subvol->graph->id);
  506             }
  507 
  508             resolve->op_ret = -1;
  509             resolve->op_errno = EBADF;
  510         } else {
  511             gf_log(state->this->name, GF_LOG_DEBUG,
  512                    "basefd (ptr:%p inode-gfid:%s) migrated "
  513                    "successfully in resolver "
  514                    "(old-subvolume:%s-%d new-subvolume:%s-%d)",
  515                    basefd, uuid_utoa(basefd->inode->gfid), active_subvol->name,
  516                    active_subvol->graph->id, state->active_subvol->name,
  517                    state->active_subvol->graph->id);
  518         }
  519     }
  520 
  521     if ((resolve->op_ret == -1) && (resolve->op_errno == EBADF)) {
  522         gf_log("fuse-resolve", GF_LOG_WARNING,
  523                "migration of basefd (ptr:%p inode-gfid:%s) "
  524                "did not complete, failing fop with EBADF "
  525                "(old-subvolume:%s-%d new-subvolume:%s-%d)",
  526                basefd, uuid_utoa(basefd->inode->gfid), active_subvol->name,
  527                active_subvol->graph->id, state->active_subvol->name,
  528                state->active_subvol->graph->id);
  529     }
  530 
  531     if (activefd != basefd) {
  532         state->fd = fd_ref(activefd);
  533         fd_unref(basefd);
  534     }
  535 
  536     /* state->active_subvol = active_subvol; */
  537 
  538 resolve_continue:
  539     if (activefd != NULL) {
  540         fd_unref(activefd);
  541     }
  542 
  543     fuse_resolve_continue(state);
  544 
  545     return 0;
  546 }
  547 
  548 int
  549 fuse_gfid_set(fuse_state_t *state)
  550 {
  551     int ret = 0;
  552 
  553     if (gf_uuid_is_null(state->gfid))
  554         goto out;
  555 
  556     if (!state->xdata)
  557         state->xdata = dict_new();
  558 
  559     if (!state->xdata) {
  560         ret = -1;
  561         goto out;
  562     }
  563 
  564     ret = dict_set_gfuuid(state->xdata, "gfid-req", state->gfid, true);
  565 out:
  566     return ret;
  567 }
  568 
  569 int
  570 fuse_resolve_entry_init(fuse_state_t *state, fuse_resolve_t *resolve, ino_t par,
  571                         char *name)
  572 {
  573     inode_t *parent = NULL;
  574 
  575     parent = fuse_ino_to_inode(par, state->this);
  576     gf_uuid_copy(resolve->pargfid, parent->gfid);
  577     resolve->parhint = parent;
  578     resolve->bname = gf_strdup(name);
  579 
  580     return 0;
  581 }
  582 
  583 int
  584 fuse_resolve_inode_init(fuse_state_t *state, fuse_resolve_t *resolve, ino_t ino)
  585 {
  586     inode_t *inode = NULL;
  587 
  588     inode = fuse_ino_to_inode(ino, state->this);
  589     gf_uuid_copy(resolve->gfid, inode->gfid);
  590     resolve->hint = inode;
  591 
  592     return 0;
  593 }
  594 
  595 int
  596 fuse_resolve_fd_init(fuse_state_t *state, fuse_resolve_t *resolve, fd_t *fd)
  597 {
  598     resolve->fd = fd_ref(fd);
  599 
  600     return 0;
  601 }
  602 
  603 static int
  604 fuse_resolve(fuse_state_t *state)
  605 {
  606     fuse_resolve_t *resolve = NULL;
  607 
  608     resolve = state->resolve_now;
  609 
  610     if (resolve->fd) {
  611         fuse_resolve_fd(state);
  612 
  613     } else if (!gf_uuid_is_null(resolve->pargfid)) {
  614         fuse_resolve_parent(state);
  615 
  616     } else if (!gf_uuid_is_null(resolve->gfid)) {
  617         fuse_resolve_inode(state);
  618 
  619     } else {
  620         fuse_resolve_all(state);
  621     }
  622 
  623     return 0;
  624 }
  625 
  626 static int
  627 fuse_resolve_done(fuse_state_t *state)
  628 {
  629     fuse_fop_resume(state);
  630     return 0;
  631 }
  632 
  633 /*
  634  * This function is called multiple times, once per resolving one location/fd.
  635  * state->resolve_now is used to decide which location/fd is to be resolved now
  636  */
  637 static int
  638 fuse_resolve_all(fuse_state_t *state)
  639 {
  640     if (state->resolve_now == NULL) {
  641         state->resolve_now = &state->resolve;
  642         state->loc_now = &state->loc;
  643 
  644         fuse_resolve(state);
  645 
  646     } else if (state->resolve_now == &state->resolve) {
  647         state->resolve_now = &state->resolve2;
  648         state->loc_now = &state->loc2;
  649 
  650         fuse_resolve(state);
  651 
  652     } else if (state->resolve_now == &state->resolve2) {
  653         fuse_resolve_done(state);
  654 
  655     } else {
  656         gf_log("fuse-resolve", GF_LOG_ERROR,
  657                "Invalid pointer for state->resolve_now");
  658     }
  659 
  660     return 0;
  661 }
  662 
  663 int
  664 fuse_resolve_continue(fuse_state_t *state)
  665 {
  666     fuse_resolve_loc_touchup(state);
  667 
  668     fuse_resolve_all(state);
  669 
  670     return 0;
  671 }
  672 
  673 int
  674 fuse_resolve_and_resume(fuse_state_t *state, fuse_resume_fn_t fn)
  675 {
  676     fuse_gfid_set(state);
  677 
  678     state->resume_fn = fn;
  679 
  680     fuse_resolve_all(state);
  681 
  682     return 0;
  683 }