The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/lib/libzfs/libzfs_iter.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or https://opensource.org/licenses/CDDL-1.0.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 
   22 /*
   23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
   24  * Copyright (c) 2013, 2019 by Delphix. All rights reserved.
   25  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
   26  * Copyright (c) 2019 Datto Inc.
   27  */
   28 
   29 #include <stdio.h>
   30 #include <stdlib.h>
   31 #include <string.h>
   32 #include <unistd.h>
   33 #include <stddef.h>
   34 #include <libintl.h>
   35 #include <libzfs.h>
   36 #include <libzutil.h>
   37 #include <sys/mntent.h>
   38 
   39 #include "libzfs_impl.h"
   40 
   41 static int
   42 zfs_iter_clones(zfs_handle_t *zhp, int flags __maybe_unused, zfs_iter_f func,
   43     void *data)
   44 {
   45         nvlist_t *nvl = zfs_get_clones_nvl(zhp);
   46         nvpair_t *pair;
   47 
   48         if (nvl == NULL)
   49                 return (0);
   50 
   51         for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL;
   52             pair = nvlist_next_nvpair(nvl, pair)) {
   53                 zfs_handle_t *clone = zfs_open(zhp->zfs_hdl, nvpair_name(pair),
   54                     ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
   55                 if (clone != NULL) {
   56                         int err = func(clone, data);
   57                         if (err != 0)
   58                                 return (err);
   59                 }
   60         }
   61         return (0);
   62 }
   63 
   64 static int
   65 zfs_do_list_ioctl(zfs_handle_t *zhp, int arg, zfs_cmd_t *zc)
   66 {
   67         int rc;
   68         uint64_t        orig_cookie;
   69 
   70         orig_cookie = zc->zc_cookie;
   71 top:
   72         (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
   73         zc->zc_objset_stats.dds_creation_txg = 0;
   74         rc = zfs_ioctl(zhp->zfs_hdl, arg, zc);
   75 
   76         if (rc == -1) {
   77                 switch (errno) {
   78                 case ENOMEM:
   79                         /* expand nvlist memory and try again */
   80                         zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc);
   81                         zc->zc_cookie = orig_cookie;
   82                         goto top;
   83                 /*
   84                  * An errno value of ESRCH indicates normal completion.
   85                  * If ENOENT is returned, then the underlying dataset
   86                  * has been removed since we obtained the handle.
   87                  */
   88                 case ESRCH:
   89                 case ENOENT:
   90                         rc = 1;
   91                         break;
   92                 default:
   93                         rc = zfs_standard_error(zhp->zfs_hdl, errno,
   94                             dgettext(TEXT_DOMAIN,
   95                             "cannot iterate filesystems"));
   96                         break;
   97                 }
   98         }
   99         return (rc);
  100 }
  101 
  102 /*
  103  * Iterate over all child filesystems
  104  */
  105 int
  106 zfs_iter_filesystems(zfs_handle_t *zhp, int flags, zfs_iter_f func, void *data)
  107 {
  108         zfs_cmd_t zc = {"\0"};
  109         zfs_handle_t *nzhp;
  110         int ret;
  111 
  112         if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
  113                 return (0);
  114 
  115         zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0);
  116 
  117         if ((flags & ZFS_ITER_SIMPLE) == ZFS_ITER_SIMPLE)
  118                 zc.zc_simple = B_TRUE;
  119 
  120         while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT,
  121             &zc)) == 0) {
  122                 if (zc.zc_simple)
  123                         nzhp = make_dataset_simple_handle_zc(zhp, &zc);
  124                 else
  125                         nzhp = make_dataset_handle_zc(zhp->zfs_hdl, &zc);
  126                 /*
  127                  * Silently ignore errors, as the only plausible explanation is
  128                  * that the pool has since been removed.
  129                  */
  130                 if (nzhp == NULL)
  131                         continue;
  132 
  133                 if ((ret = func(nzhp, data)) != 0) {
  134                         zcmd_free_nvlists(&zc);
  135                         return (ret);
  136                 }
  137         }
  138         zcmd_free_nvlists(&zc);
  139         return ((ret < 0) ? ret : 0);
  140 }
  141 
  142 /*
  143  * Iterate over all snapshots
  144  */
  145 int
  146 zfs_iter_snapshots(zfs_handle_t *zhp, int flags, zfs_iter_f func,
  147     void *data, uint64_t min_txg, uint64_t max_txg)
  148 {
  149         zfs_cmd_t zc = {"\0"};
  150         zfs_handle_t *nzhp;
  151         int ret;
  152         nvlist_t *range_nvl = NULL;
  153 
  154         if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
  155             zhp->zfs_type == ZFS_TYPE_BOOKMARK)
  156                 return (0);
  157 
  158         zc.zc_simple = (flags & ZFS_ITER_SIMPLE) != 0;
  159 
  160         zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0);
  161 
  162         if (min_txg != 0) {
  163                 range_nvl = fnvlist_alloc();
  164                 fnvlist_add_uint64(range_nvl, SNAP_ITER_MIN_TXG, min_txg);
  165         }
  166         if (max_txg != 0) {
  167                 if (range_nvl == NULL)
  168                         range_nvl = fnvlist_alloc();
  169                 fnvlist_add_uint64(range_nvl, SNAP_ITER_MAX_TXG, max_txg);
  170         }
  171 
  172         if (range_nvl != NULL)
  173                 zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, range_nvl);
  174 
  175         while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
  176             &zc)) == 0) {
  177 
  178                 if (zc.zc_simple)
  179                         nzhp = make_dataset_simple_handle_zc(zhp, &zc);
  180                 else
  181                         nzhp = make_dataset_handle_zc(zhp->zfs_hdl, &zc);
  182                 if (nzhp == NULL)
  183                         continue;
  184 
  185                 if ((ret = func(nzhp, data)) != 0) {
  186                         zcmd_free_nvlists(&zc);
  187                         fnvlist_free(range_nvl);
  188                         return (ret);
  189                 }
  190         }
  191         zcmd_free_nvlists(&zc);
  192         fnvlist_free(range_nvl);
  193         return ((ret < 0) ? ret : 0);
  194 }
  195 
  196 /*
  197  * Iterate over all bookmarks
  198  */
  199 int
  200 zfs_iter_bookmarks(zfs_handle_t *zhp, int flags __maybe_unused,
  201     zfs_iter_f func, void *data)
  202 {
  203         zfs_handle_t *nzhp;
  204         nvlist_t *props = NULL;
  205         nvlist_t *bmarks = NULL;
  206         int err;
  207         nvpair_t *pair;
  208 
  209         if ((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK)) != 0)
  210                 return (0);
  211 
  212         /* Setup the requested properties nvlist. */
  213         props = fnvlist_alloc();
  214         for (zfs_prop_t p = 0; p < ZFS_NUM_PROPS; p++) {
  215                 if (zfs_prop_valid_for_type(p, ZFS_TYPE_BOOKMARK, B_FALSE)) {
  216                         fnvlist_add_boolean(props, zfs_prop_to_name(p));
  217                 }
  218         }
  219         fnvlist_add_boolean(props, "redact_complete");
  220 
  221         if ((err = lzc_get_bookmarks(zhp->zfs_name, props, &bmarks)) != 0)
  222                 goto out;
  223 
  224         for (pair = nvlist_next_nvpair(bmarks, NULL);
  225             pair != NULL; pair = nvlist_next_nvpair(bmarks, pair)) {
  226                 char name[ZFS_MAX_DATASET_NAME_LEN];
  227                 char *bmark_name;
  228                 nvlist_t *bmark_props;
  229 
  230                 bmark_name = nvpair_name(pair);
  231                 bmark_props = fnvpair_value_nvlist(pair);
  232 
  233                 if (snprintf(name, sizeof (name), "%s#%s", zhp->zfs_name,
  234                     bmark_name) >= sizeof (name)) {
  235                         err = EINVAL;
  236                         goto out;
  237                 }
  238 
  239                 nzhp = make_bookmark_handle(zhp, name, bmark_props);
  240                 if (nzhp == NULL)
  241                         continue;
  242 
  243                 if ((err = func(nzhp, data)) != 0)
  244                         goto out;
  245         }
  246 
  247 out:
  248         fnvlist_free(props);
  249         fnvlist_free(bmarks);
  250 
  251         return (err);
  252 }
  253 
  254 /*
  255  * Routines for dealing with the sorted snapshot functionality
  256  */
  257 typedef struct zfs_node {
  258         zfs_handle_t    *zn_handle;
  259         avl_node_t      zn_avlnode;
  260 } zfs_node_t;
  261 
  262 static int
  263 zfs_sort_snaps(zfs_handle_t *zhp, void *data)
  264 {
  265         avl_tree_t *avl = data;
  266         zfs_node_t *node;
  267         zfs_node_t search;
  268 
  269         search.zn_handle = zhp;
  270         node = avl_find(avl, &search, NULL);
  271         if (node) {
  272                 /*
  273                  * If this snapshot was renamed while we were creating the
  274                  * AVL tree, it's possible that we already inserted it under
  275                  * its old name. Remove the old handle before adding the new
  276                  * one.
  277                  */
  278                 zfs_close(node->zn_handle);
  279                 avl_remove(avl, node);
  280                 free(node);
  281         }
  282 
  283         node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t));
  284         node->zn_handle = zhp;
  285         avl_add(avl, node);
  286 
  287         return (0);
  288 }
  289 
  290 static int
  291 zfs_snapshot_compare(const void *larg, const void *rarg)
  292 {
  293         zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
  294         zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
  295         uint64_t lcreate, rcreate;
  296 
  297         /*
  298          * Sort them according to creation time.  We use the hidden
  299          * CREATETXG property to get an absolute ordering of snapshots.
  300          */
  301         lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
  302         rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
  303 
  304         return (TREE_CMP(lcreate, rcreate));
  305 }
  306 
  307 int
  308 zfs_iter_snapshots_sorted(zfs_handle_t *zhp, int flags, zfs_iter_f callback,
  309     void *data, uint64_t min_txg, uint64_t max_txg)
  310 {
  311         int ret = 0;
  312         zfs_node_t *node;
  313         avl_tree_t avl;
  314         void *cookie = NULL;
  315 
  316         avl_create(&avl, zfs_snapshot_compare,
  317             sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode));
  318 
  319         ret = zfs_iter_snapshots(zhp, flags, zfs_sort_snaps, &avl, min_txg,
  320             max_txg);
  321 
  322         for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
  323                 ret |= callback(node->zn_handle, data);
  324 
  325         while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL)
  326                 free(node);
  327 
  328         avl_destroy(&avl);
  329 
  330         return (ret);
  331 }
  332 
  333 typedef struct {
  334         char *ssa_first;
  335         char *ssa_last;
  336         boolean_t ssa_seenfirst;
  337         boolean_t ssa_seenlast;
  338         zfs_iter_f ssa_func;
  339         void *ssa_arg;
  340 } snapspec_arg_t;
  341 
  342 static int
  343 snapspec_cb(zfs_handle_t *zhp, void *arg)
  344 {
  345         snapspec_arg_t *ssa = arg;
  346         const char *shortsnapname;
  347         int err = 0;
  348 
  349         if (ssa->ssa_seenlast)
  350                 return (0);
  351 
  352         shortsnapname = strchr(zfs_get_name(zhp), '@') + 1;
  353         if (!ssa->ssa_seenfirst && strcmp(shortsnapname, ssa->ssa_first) == 0)
  354                 ssa->ssa_seenfirst = B_TRUE;
  355         if (strcmp(shortsnapname, ssa->ssa_last) == 0)
  356                 ssa->ssa_seenlast = B_TRUE;
  357 
  358         if (ssa->ssa_seenfirst) {
  359                 err = ssa->ssa_func(zhp, ssa->ssa_arg);
  360         } else {
  361                 zfs_close(zhp);
  362         }
  363 
  364         return (err);
  365 }
  366 
  367 /*
  368  * spec is a string like "A,B%C,D"
  369  *
  370  * <snaps>, where <snaps> can be:
  371  *      <snap>          (single snapshot)
  372  *      <snap>%<snap>   (range of snapshots, inclusive)
  373  *      %<snap>         (range of snapshots, starting with earliest)
  374  *      <snap>%         (range of snapshots, ending with last)
  375  *      %               (all snapshots)
  376  *      <snaps>[,...]   (comma separated list of the above)
  377  *
  378  * If a snapshot can not be opened, continue trying to open the others, but
  379  * return ENOENT at the end.
  380  */
  381 int
  382 zfs_iter_snapspec(zfs_handle_t *fs_zhp, int flags, const char *spec_orig,
  383     zfs_iter_f func, void *arg)
  384 {
  385         char *buf, *comma_separated, *cp;
  386         int err = 0;
  387         int ret = 0;
  388 
  389         buf = zfs_strdup(fs_zhp->zfs_hdl, spec_orig);
  390         cp = buf;
  391 
  392         while ((comma_separated = strsep(&cp, ",")) != NULL) {
  393                 char *pct = strchr(comma_separated, '%');
  394                 if (pct != NULL) {
  395                         snapspec_arg_t ssa = { 0 };
  396                         ssa.ssa_func = func;
  397                         ssa.ssa_arg = arg;
  398 
  399                         if (pct == comma_separated)
  400                                 ssa.ssa_seenfirst = B_TRUE;
  401                         else
  402                                 ssa.ssa_first = comma_separated;
  403                         *pct = '\0';
  404                         ssa.ssa_last = pct + 1;
  405 
  406                         /*
  407                          * If there is a lastname specified, make sure it
  408                          * exists.
  409                          */
  410                         if (ssa.ssa_last[0] != '\0') {
  411                                 char snapname[ZFS_MAX_DATASET_NAME_LEN];
  412                                 (void) snprintf(snapname, sizeof (snapname),
  413                                     "%s@%s", zfs_get_name(fs_zhp),
  414                                     ssa.ssa_last);
  415                                 if (!zfs_dataset_exists(fs_zhp->zfs_hdl,
  416                                     snapname, ZFS_TYPE_SNAPSHOT)) {
  417                                         ret = ENOENT;
  418                                         continue;
  419                                 }
  420                         }
  421 
  422                         err = zfs_iter_snapshots_sorted(fs_zhp, flags,
  423                             snapspec_cb, &ssa, 0, 0);
  424                         if (ret == 0)
  425                                 ret = err;
  426                         if (ret == 0 && (!ssa.ssa_seenfirst ||
  427                             (ssa.ssa_last[0] != '\0' && !ssa.ssa_seenlast))) {
  428                                 ret = ENOENT;
  429                         }
  430                 } else {
  431                         char snapname[ZFS_MAX_DATASET_NAME_LEN];
  432                         zfs_handle_t *snap_zhp;
  433                         (void) snprintf(snapname, sizeof (snapname), "%s@%s",
  434                             zfs_get_name(fs_zhp), comma_separated);
  435                         snap_zhp = make_dataset_handle(fs_zhp->zfs_hdl,
  436                             snapname);
  437                         if (snap_zhp == NULL) {
  438                                 ret = ENOENT;
  439                                 continue;
  440                         }
  441                         err = func(snap_zhp, arg);
  442                         if (ret == 0)
  443                                 ret = err;
  444                 }
  445         }
  446 
  447         free(buf);
  448         return (ret);
  449 }
  450 
  451 /*
  452  * Iterate over all children, snapshots and filesystems
  453  * Process snapshots before filesystems because they are nearer the input
  454  * handle: this is extremely important when used with zfs_iter_f functions
  455  * looking for data, following the logic that we would like to find it as soon
  456  * and as close as possible.
  457  */
  458 int
  459 zfs_iter_children(zfs_handle_t *zhp, int flags, zfs_iter_f func, void *data)
  460 {
  461         int ret;
  462 
  463         if ((ret = zfs_iter_snapshots(zhp, flags, func, data, 0, 0)) != 0)
  464                 return (ret);
  465 
  466         return (zfs_iter_filesystems(zhp, flags, func, data));
  467 }
  468 
  469 
  470 typedef struct iter_stack_frame {
  471         struct iter_stack_frame *next;
  472         zfs_handle_t *zhp;
  473 } iter_stack_frame_t;
  474 
  475 typedef struct iter_dependents_arg {
  476         boolean_t first;
  477         int flags;
  478         boolean_t allowrecursion;
  479         iter_stack_frame_t *stack;
  480         zfs_iter_f func;
  481         void *data;
  482 } iter_dependents_arg_t;
  483 
  484 static int
  485 iter_dependents_cb(zfs_handle_t *zhp, void *arg)
  486 {
  487         iter_dependents_arg_t *ida = arg;
  488         int err = 0;
  489         boolean_t first = ida->first;
  490         ida->first = B_FALSE;
  491 
  492         if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
  493                 err = zfs_iter_clones(zhp, ida->flags, iter_dependents_cb, ida);
  494         } else if (zhp->zfs_type != ZFS_TYPE_BOOKMARK) {
  495                 iter_stack_frame_t isf;
  496                 iter_stack_frame_t *f;
  497 
  498                 /*
  499                  * check if there is a cycle by seeing if this fs is already
  500                  * on the stack.
  501                  */
  502                 for (f = ida->stack; f != NULL; f = f->next) {
  503                         if (f->zhp->zfs_dmustats.dds_guid ==
  504                             zhp->zfs_dmustats.dds_guid) {
  505                                 if (ida->allowrecursion) {
  506                                         zfs_close(zhp);
  507                                         return (0);
  508                                 } else {
  509                                         zfs_error_aux(zhp->zfs_hdl,
  510                                             dgettext(TEXT_DOMAIN,
  511                                             "recursive dependency at '%s'"),
  512                                             zfs_get_name(zhp));
  513                                         err = zfs_error(zhp->zfs_hdl,
  514                                             EZFS_RECURSIVE,
  515                                             dgettext(TEXT_DOMAIN,
  516                                             "cannot determine dependent "
  517                                             "datasets"));
  518                                         zfs_close(zhp);
  519                                         return (err);
  520                                 }
  521                         }
  522                 }
  523 
  524                 isf.zhp = zhp;
  525                 isf.next = ida->stack;
  526                 ida->stack = &isf;
  527                 err = zfs_iter_filesystems(zhp, ida->flags,
  528                     iter_dependents_cb, ida);
  529                 if (err == 0)
  530                         err = zfs_iter_snapshots(zhp, ida->flags,
  531                             iter_dependents_cb, ida, 0, 0);
  532                 ida->stack = isf.next;
  533         }
  534 
  535         if (!first && err == 0)
  536                 err = ida->func(zhp, ida->data);
  537         else
  538                 zfs_close(zhp);
  539 
  540         return (err);
  541 }
  542 
  543 int
  544 zfs_iter_dependents(zfs_handle_t *zhp, int flags, boolean_t allowrecursion,
  545     zfs_iter_f func, void *data)
  546 {
  547         iter_dependents_arg_t ida;
  548         ida.flags = flags;
  549         ida.allowrecursion = allowrecursion;
  550         ida.stack = NULL;
  551         ida.func = func;
  552         ida.data = data;
  553         ida.first = B_TRUE;
  554         return (iter_dependents_cb(zfs_handle_dup(zhp), &ida));
  555 }
  556 
  557 /*
  558  * Iterate over mounted children of the specified dataset
  559  */
  560 int
  561 zfs_iter_mounted(zfs_handle_t *zhp, zfs_iter_f func, void *data)
  562 {
  563         char mnt_prop[ZFS_MAXPROPLEN];
  564         struct mnttab entry;
  565         zfs_handle_t *mtab_zhp;
  566         size_t namelen = strlen(zhp->zfs_name);
  567         FILE *mnttab;
  568         int err = 0;
  569 
  570         if ((mnttab = fopen(MNTTAB, "re")) == NULL)
  571                 return (ENOENT);
  572 
  573         while (err == 0 && getmntent(mnttab, &entry) == 0) {
  574                 /* Ignore non-ZFS entries */
  575                 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
  576                         continue;
  577 
  578                 /* Ignore datasets not within the provided dataset */
  579                 if (strncmp(entry.mnt_special, zhp->zfs_name, namelen) != 0 ||
  580                     entry.mnt_special[namelen] != '/')
  581                         continue;
  582 
  583                 /* Skip snapshot of any child dataset */
  584                 if (strchr(entry.mnt_special, '@') != NULL)
  585                         continue;
  586 
  587                 if ((mtab_zhp = zfs_open(zhp->zfs_hdl, entry.mnt_special,
  588                     ZFS_TYPE_FILESYSTEM)) == NULL)
  589                         continue;
  590 
  591                 /* Ignore legacy mounts as they are user managed */
  592                 verify(zfs_prop_get(mtab_zhp, ZFS_PROP_MOUNTPOINT, mnt_prop,
  593                     sizeof (mnt_prop), NULL, NULL, 0, B_FALSE) == 0);
  594                 if (strcmp(mnt_prop, "legacy") == 0) {
  595                         zfs_close(mtab_zhp);
  596                         continue;
  597                 }
  598 
  599                 err = func(mtab_zhp, data);
  600         }
  601 
  602         fclose(mnttab);
  603 
  604         return (err);
  605 }

Cache object: 17dd735d9a5a928151bcf1a0fe6efd8b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.