Home | History | Annotate | Line # | Download | only in zfs
      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 http://www.opensolaris.org/os/licensing.
     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 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/conf.h>
     31 #include <sys/sunddi.h>
     32 #include <sys/zfs_ioctl.h>
     33 #include <sys/zfs_onexit.h>
     34 #include <sys/zvol.h>
     35 
     36 /*
     37  * ZFS kernel routines may add/delete callback routines to be invoked
     38  * upon process exit (triggered via the close operation from the /dev/zfs
     39  * driver).
     40  *
     41  * These cleanup callbacks are intended to allow for the accumulation
     42  * of kernel state across multiple ioctls.  User processes participate
     43  * by opening ZFS_DEV with O_EXCL. This causes the ZFS driver to do a
     44  * clone-open, generating a unique minor number. The process then passes
     45  * along that file descriptor to 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 static int
    105 zfs_onexit_minor_to_state(minor_t minor, zfs_onexit_t **zo)
    106 {
    107 	*zo = zfsdev_get_soft_state(minor, ZSST_CTLDEV);
    108 	if (*zo == NULL)
    109 		return (SET_ERROR(EBADF));
    110 
    111 	return (0);
    112 }
    113 
    114 /*
    115  * Consumers might need to operate by minor number instead of fd, since
    116  * they might be running in another thread (e.g. txg_sync_thread). Callers
    117  * of this function must call zfs_onexit_fd_rele() when they're finished
    118  * using the minor number.
    119  */
    120 int
    121 zfs_onexit_fd_hold(int fd, minor_t *minorp)
    122 {
    123 	file_t *fp;
    124 	zfs_onexit_t *zo;
    125 
    126 #ifdef __FreeBSD__
    127 	file_t *tmpfp;
    128 	cap_rights_t rights;
    129 	void *data;
    130 	int error;
    131 
    132 	fp = getf(fd, cap_rights_init(&rights));
    133 	if (fp == NULL)
    134 		return (SET_ERROR(EBADF));
    135 
    136 	tmpfp = curthread->td_fpop;
    137 	curthread->td_fpop = fp;
    138 	error = devfs_get_cdevpriv(&data);
    139 	if (error == 0)
    140 		*minorp = (minor_t)(uintptr_t)data;
    141 	curthread->td_fpop = tmpfp;
    142 	if (error != 0)
    143 		return (SET_ERROR(EBADF));
    144 #else
    145 	fp = getf(fd);
    146 	if (fp == NULL)
    147 		return (SET_ERROR(EBADF));
    148 
    149 	ASSERT(strcmp(fp->f_ops->fo_name, "zfs") == 0);
    150 	*minorp = minor((dev_t)(uintptr_t)fp->f_data);
    151 #endif
    152 
    153 	return (zfs_onexit_minor_to_state(*minorp, &zo));
    154 }
    155 
    156 void
    157 zfs_onexit_fd_rele(int fd)
    158 {
    159 	releasef(fd);
    160 }
    161 
    162 /*
    163  * Add a callback to be invoked when the calling process exits.
    164  */
    165 int
    166 zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data,
    167     uint64_t *action_handle)
    168 {
    169 	zfs_onexit_t *zo;
    170 	zfs_onexit_action_node_t *ap;
    171 	int error;
    172 
    173 	error = zfs_onexit_minor_to_state(minor, &zo);
    174 	if (error)
    175 		return (error);
    176 
    177 	ap = kmem_alloc(sizeof (zfs_onexit_action_node_t), KM_SLEEP);
    178 	list_link_init(&ap->za_link);
    179 	ap->za_func = func;
    180 	ap->za_data = data;
    181 
    182 	mutex_enter(&zo->zo_lock);
    183 	list_insert_tail(&zo->zo_actions, ap);
    184 	mutex_exit(&zo->zo_lock);
    185 	if (action_handle)
    186 		*action_handle = (uint64_t)(uintptr_t)ap;
    187 
    188 	return (0);
    189 }
    190 
    191 static zfs_onexit_action_node_t *
    192 zfs_onexit_find_cb(zfs_onexit_t *zo, uint64_t action_handle)
    193 {
    194 	zfs_onexit_action_node_t *match;
    195 	zfs_onexit_action_node_t *ap;
    196 	list_t *l;
    197 
    198 	ASSERT(MUTEX_HELD(&zo->zo_lock));
    199 
    200 	match = (zfs_onexit_action_node_t *)(uintptr_t)action_handle;
    201 	l = &zo->zo_actions;
    202 	for (ap = list_head(l); ap != NULL; ap = list_next(l, ap)) {
    203 		if (match == ap)
    204 			break;
    205 	}
    206 	return (ap);
    207 }
    208 
    209 /*
    210  * Delete the callback, triggering it first if 'fire' is set.
    211  */
    212 int
    213 zfs_onexit_del_cb(minor_t minor, uint64_t action_handle, boolean_t fire)
    214 {
    215 	zfs_onexit_t *zo;
    216 	zfs_onexit_action_node_t *ap;
    217 	int error;
    218 
    219 	error = zfs_onexit_minor_to_state(minor, &zo);
    220 	if (error)
    221 		return (error);
    222 
    223 	mutex_enter(&zo->zo_lock);
    224 	ap = zfs_onexit_find_cb(zo, action_handle);
    225 	if (ap != NULL) {
    226 		list_remove(&zo->zo_actions, ap);
    227 		mutex_exit(&zo->zo_lock);
    228 		if (fire)
    229 			ap->za_func(ap->za_data);
    230 		kmem_free(ap, sizeof (zfs_onexit_action_node_t));
    231 	} else {
    232 		mutex_exit(&zo->zo_lock);
    233 		error = SET_ERROR(ENOENT);
    234 	}
    235 
    236 	return (error);
    237 }
    238 
    239 /*
    240  * Return the data associated with this callback.  This allows consumers
    241  * of the cleanup-on-exit interfaces to stash kernel data across system
    242  * calls, knowing that it will be cleaned up if the calling process exits.
    243  */
    244 int
    245 zfs_onexit_cb_data(minor_t minor, uint64_t action_handle, void **data)
    246 {
    247 	zfs_onexit_t *zo;
    248 	zfs_onexit_action_node_t *ap;
    249 	int error;
    250 
    251 	*data = NULL;
    252 
    253 	error = zfs_onexit_minor_to_state(minor, &zo);
    254 	if (error)
    255 		return (error);
    256 
    257 	mutex_enter(&zo->zo_lock);
    258 	ap = zfs_onexit_find_cb(zo, action_handle);
    259 	if (ap != NULL)
    260 		*data = ap->za_data;
    261 	else
    262 		error = SET_ERROR(ENOENT);
    263 	mutex_exit(&zo->zo_lock);
    264 
    265 	return (error);
    266 }
    267