zfs_onexit.c revision 282760
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 73void 74zfs_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 84void 85zfs_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 104static int 105zfs_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 */ 120int 121zfs_onexit_fd_hold(int fd, minor_t *minorp) 122{ 123 file_t *fp, *tmpfp; 124 zfs_onexit_t *zo; 125 cap_rights_t rights; 126 void *data; 127 int error; 128 129 fp = getf(fd, cap_rights_init(&rights)); 130 if (fp == NULL) 131 return (SET_ERROR(EBADF)); 132 133 tmpfp = curthread->td_fpop; 134 curthread->td_fpop = fp; 135 error = devfs_get_cdevpriv(&data); 136 if (error == 0) 137 *minorp = (minor_t)(uintptr_t)data; 138 curthread->td_fpop = tmpfp; 139 if (error != 0) 140 return (SET_ERROR(EBADF)); 141 return (zfs_onexit_minor_to_state(*minorp, &zo)); 142} 143 144void 145zfs_onexit_fd_rele(int fd) 146{ 147 releasef(fd); 148} 149 150/* 151 * Add a callback to be invoked when the calling process exits. 152 */ 153int 154zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data, 155 uint64_t *action_handle) 156{ 157 zfs_onexit_t *zo; 158 zfs_onexit_action_node_t *ap; 159 int error; 160 161 error = zfs_onexit_minor_to_state(minor, &zo); 162 if (error) 163 return (error); 164 165 ap = kmem_alloc(sizeof (zfs_onexit_action_node_t), KM_SLEEP); 166 list_link_init(&ap->za_link); 167 ap->za_func = func; 168 ap->za_data = data; 169 170 mutex_enter(&zo->zo_lock); 171 list_insert_tail(&zo->zo_actions, ap); 172 mutex_exit(&zo->zo_lock); 173 if (action_handle) 174 *action_handle = (uint64_t)(uintptr_t)ap; 175 176 return (0); 177} 178 179static zfs_onexit_action_node_t * 180zfs_onexit_find_cb(zfs_onexit_t *zo, uint64_t action_handle) 181{ 182 zfs_onexit_action_node_t *match; 183 zfs_onexit_action_node_t *ap; 184 list_t *l; 185 186 ASSERT(MUTEX_HELD(&zo->zo_lock)); 187 188 match = (zfs_onexit_action_node_t *)(uintptr_t)action_handle; 189 l = &zo->zo_actions; 190 for (ap = list_head(l); ap != NULL; ap = list_next(l, ap)) { 191 if (match == ap) 192 break; 193 } 194 return (ap); 195} 196 197/* 198 * Delete the callback, triggering it first if 'fire' is set. 199 */ 200int 201zfs_onexit_del_cb(minor_t minor, uint64_t action_handle, boolean_t fire) 202{ 203 zfs_onexit_t *zo; 204 zfs_onexit_action_node_t *ap; 205 int error; 206 207 error = zfs_onexit_minor_to_state(minor, &zo); 208 if (error) 209 return (error); 210 211 mutex_enter(&zo->zo_lock); 212 ap = zfs_onexit_find_cb(zo, action_handle); 213 if (ap != NULL) { 214 list_remove(&zo->zo_actions, ap); 215 mutex_exit(&zo->zo_lock); 216 if (fire) 217 ap->za_func(ap->za_data); 218 kmem_free(ap, sizeof (zfs_onexit_action_node_t)); 219 } else { 220 mutex_exit(&zo->zo_lock); 221 error = SET_ERROR(ENOENT); 222 } 223 224 return (error); 225} 226 227/* 228 * Return the data associated with this callback. This allows consumers 229 * of the cleanup-on-exit interfaces to stash kernel data across system 230 * calls, knowing that it will be cleaned up if the calling process exits. 231 */ 232int 233zfs_onexit_cb_data(minor_t minor, uint64_t action_handle, void **data) 234{ 235 zfs_onexit_t *zo; 236 zfs_onexit_action_node_t *ap; 237 int error; 238 239 *data = NULL; 240 241 error = zfs_onexit_minor_to_state(minor, &zo); 242 if (error) 243 return (error); 244 245 mutex_enter(&zo->zo_lock); 246 ap = zfs_onexit_find_cb(zo, action_handle); 247 if (ap != NULL) 248 *data = ap->za_data; 249 else 250 error = SET_ERROR(ENOENT); 251 mutex_exit(&zo->zo_lock); 252 253 return (error); 254} 255