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/module/zfs/zfs_onexit.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  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
   23  * Copyright (c) 2013, 2020 by Delphix. All rights reserved.
   24  */
   25 
   26 #include <sys/types.h>
   27 #include <sys/param.h>
   28 #include <sys/errno.h>
   29 #include <sys/kmem.h>
   30 #include <sys/sunddi.h>
   31 #include <sys/zfs_ioctl.h>
   32 #include <sys/zfs_onexit.h>
   33 #include <sys/zvol.h>
   34 
   35 /*
   36  * ZFS kernel routines may add/delete callback routines to be invoked
   37  * upon process exit (triggered via the close operation from the /dev/zfs
   38  * driver).
   39  *
   40  * These cleanup callbacks are intended to allow for the accumulation
   41  * of kernel state across multiple ioctls.  User processes participate
   42  * simply by opening ZFS_DEV. This causes the ZFS driver to do create
   43  * some private data for the file descriptor and generating a unique
   44  * minor number. The process then passes along that file descriptor to
   45  * each ioctl that might have a cleanup operation.
   46  *
   47  * Consumers of the onexit routines should call zfs_onexit_fd_hold() early
   48  * on to validate the given fd and add a reference to its file table entry.
   49  * This allows the consumer to do its work and then add a callback, knowing
   50  * that zfs_onexit_add_cb() won't fail with EBADF.  When finished, consumers
   51  * should call zfs_onexit_fd_rele().
   52  *
   53  * A simple example is zfs_ioc_recv(), where we might create an AVL tree
   54  * with dataset/GUID mappings and then reuse that tree on subsequent
   55  * zfs_ioc_recv() calls.
   56  *
   57  * On the first zfs_ioc_recv() call, dmu_recv_stream() will kmem_alloc()
   58  * the AVL tree and pass it along with a callback function to
   59  * zfs_onexit_add_cb(). The zfs_onexit_add_cb() routine will register the
   60  * callback and return an action handle.
   61  *
   62  * The action handle is then passed from user space to subsequent
   63  * zfs_ioc_recv() calls, so that dmu_recv_stream() can fetch its AVL tree
   64  * by calling zfs_onexit_cb_data() with the device minor number and
   65  * action handle.
   66  *
   67  * If the user process exits abnormally, the callback is invoked implicitly
   68  * as part of the driver close operation.  Once the user space process is
   69  * finished with the accumulated kernel state, it can also just call close(2)
   70  * on the cleanup fd to trigger the cleanup callback.
   71  */
   72 
   73 void
   74 zfs_onexit_init(zfs_onexit_t **zop)
   75 {
   76         zfs_onexit_t *zo;
   77 
   78         zo = *zop = kmem_zalloc(sizeof (zfs_onexit_t), KM_SLEEP);
   79         mutex_init(&zo->zo_lock, NULL, MUTEX_DEFAULT, NULL);
   80         list_create(&zo->zo_actions, sizeof (zfs_onexit_action_node_t),
   81             offsetof(zfs_onexit_action_node_t, za_link));
   82 }
   83 
   84 void
   85 zfs_onexit_destroy(zfs_onexit_t *zo)
   86 {
   87         zfs_onexit_action_node_t *ap;
   88 
   89         mutex_enter(&zo->zo_lock);
   90         while ((ap = list_head(&zo->zo_actions)) != NULL) {
   91                 list_remove(&zo->zo_actions, ap);
   92                 mutex_exit(&zo->zo_lock);
   93                 ap->za_func(ap->za_data);
   94                 kmem_free(ap, sizeof (zfs_onexit_action_node_t));
   95                 mutex_enter(&zo->zo_lock);
   96         }
   97         mutex_exit(&zo->zo_lock);
   98 
   99         list_destroy(&zo->zo_actions);
  100         mutex_destroy(&zo->zo_lock);
  101         kmem_free(zo, sizeof (zfs_onexit_t));
  102 }
  103 
  104 /*
  105  * Consumers might need to operate by minor number instead of fd, since
  106  * they might be running in another thread (e.g. txg_sync_thread). Callers
  107  * of this function must call zfs_onexit_fd_rele() when they're finished
  108  * using the minor number.
  109  */
  110 zfs_file_t *
  111 zfs_onexit_fd_hold(int fd, minor_t *minorp)
  112 {
  113         zfs_onexit_t *zo = NULL;
  114 
  115         zfs_file_t *fp = zfs_file_get(fd);
  116         if (fp == NULL)
  117                 return (NULL);
  118 
  119         int error = zfsdev_getminor(fp, minorp);
  120         if (error) {
  121                 zfs_onexit_fd_rele(fp);
  122                 return (NULL);
  123         }
  124 
  125         zo = zfsdev_get_state(*minorp, ZST_ONEXIT);
  126         if (zo == NULL) {
  127                 zfs_onexit_fd_rele(fp);
  128                 return (NULL);
  129         }
  130         return (fp);
  131 }
  132 
  133 void
  134 zfs_onexit_fd_rele(zfs_file_t *fp)
  135 {
  136         zfs_file_put(fp);
  137 }
  138 
  139 static int
  140 zfs_onexit_minor_to_state(minor_t minor, zfs_onexit_t **zo)
  141 {
  142         *zo = zfsdev_get_state(minor, ZST_ONEXIT);
  143         if (*zo == NULL)
  144                 return (SET_ERROR(EBADF));
  145 
  146         return (0);
  147 }
  148 
  149 /*
  150  * Add a callback to be invoked when the calling process exits.
  151  */
  152 int
  153 zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data,
  154     uintptr_t *action_handle)
  155 {
  156         zfs_onexit_t *zo;
  157         zfs_onexit_action_node_t *ap;
  158         int error;
  159 
  160         error = zfs_onexit_minor_to_state(minor, &zo);
  161         if (error)
  162                 return (error);
  163 
  164         ap = kmem_alloc(sizeof (zfs_onexit_action_node_t), KM_SLEEP);
  165         list_link_init(&ap->za_link);
  166         ap->za_func = func;
  167         ap->za_data = data;
  168 
  169         mutex_enter(&zo->zo_lock);
  170         list_insert_tail(&zo->zo_actions, ap);
  171         mutex_exit(&zo->zo_lock);
  172         if (action_handle)
  173                 *action_handle = (uintptr_t)ap;
  174 
  175         return (0);
  176 }

Cache object: 3b68a6c8b35e0536835f1acef8a50d94


[ 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.