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/open.h> 30 #include <sys/kmem.h> 31 #include <sys/conf.h> 32 #include <sys/ddi.h> 33 #include <sys/sunddi.h> 34 #include <sys/zfs_ioctl.h> 35 #include <sys/mkdev.h> 36 #include <sys/zfs_onexit.h> 37 #include <sys/zvol.h> 38 39 /* 40 * ZFS kernel routines may add/delete callback routines to be invoked 41 * upon process exit (triggered via the close operation from the /dev/zfs 42 * driver). 43 * 44 * These cleanup callbacks are intended to allow for the accumulation 45 * of kernel state across multiple ioctls. User processes participate 46 * by opening ZFS_DEV with O_EXCL. This causes the ZFS driver to do a 47 * clone-open, generating a unique minor number. The process then passes 48 * along that file descriptor to each ioctl that might have a cleanup operation. 49 * 50 * Consumers of the onexit routines should call zfs_onexit_fd_hold() early 51 * on to validate the given fd and add a reference to its file table entry. 52 * This allows the consumer to do its work and then add a callback, knowing 53 * that zfs_onexit_add_cb() won't fail with EBADF. When finished, consumers 54 * should call zfs_onexit_fd_rele(). 55 * 56 * A simple example is zfs_ioc_recv(), where we might create an AVL tree 57 * with dataset/GUID mappings and then reuse that tree on subsequent 58 * zfs_ioc_recv() calls. 59 * 60 * On the first zfs_ioc_recv() call, dmu_recv_stream() will kmem_alloc() 61 * the AVL tree and pass it along with a callback function to 62 * zfs_onexit_add_cb(). The zfs_onexit_add_cb() routine will register the 63 * callback and return an action handle. 64 * 65 * The action handle is then passed from user space to subsequent 66 * zfs_ioc_recv() calls, so that dmu_recv_stream() can fetch its AVL tree 67 * by calling zfs_onexit_cb_data() with the device minor number and 68 * action handle. 69 * 70 * If the user process exits abnormally, the callback is invoked implicitly 71 * as part of the driver close operation. Once the user space process is 72 * finished with the accumulated kernel state, it can also just call close(2) 73 * on the cleanup fd to trigger the cleanup callback. 74 */ 75 76 void 77 zfs_onexit_init(zfs_onexit_t **zop) 78 { 79 zfs_onexit_t *zo; 80 81 zo = *zop = kmem_zalloc(sizeof (zfs_onexit_t), KM_SLEEP); 82 mutex_init(&zo->zo_lock, NULL, MUTEX_DEFAULT, NULL); 83 list_create(&zo->zo_actions, sizeof (zfs_onexit_action_node_t), 84 offsetof(zfs_onexit_action_node_t, za_link)); 85 } 86 87 void 88 zfs_onexit_destroy(zfs_onexit_t *zo) 89 { 90 zfs_onexit_action_node_t *ap; 91 92 mutex_enter(&zo->zo_lock); 93 while ((ap = list_head(&zo->zo_actions)) != NULL) { 94 list_remove(&zo->zo_actions, ap); 95 mutex_exit(&zo->zo_lock); 96 ap->za_func(ap->za_data); 97 kmem_free(ap, sizeof (zfs_onexit_action_node_t)); 98 mutex_enter(&zo->zo_lock); 99 } 100 mutex_exit(&zo->zo_lock); 101 102 list_destroy(&zo->zo_actions); 103 mutex_destroy(&zo->zo_lock); 104 kmem_free(zo, sizeof (zfs_onexit_t)); 105 } 106 107 static int 108 zfs_onexit_minor_to_state(minor_t minor, zfs_onexit_t **zo) 109 { 110 *zo = zfsdev_get_soft_state(minor, ZSST_CTLDEV); 111 if (*zo == NULL) 112 return (SET_ERROR(EBADF)); 113 114 return (0); 115 } 116 117 /* 118 * Consumers might need to operate by minor number instead of fd, since 119 * they might be running in another thread (e.g. txg_sync_thread). Callers 120 * of this function must call zfs_onexit_fd_rele() when they're finished 121 * using the minor number. 122 */ 123 int 124 zfs_onexit_fd_hold(int fd, minor_t *minorp) 125 { 126 file_t *fp; 127 zfs_onexit_t *zo; 128 int ret; 129 130 fp = getf(fd); 131 if (fp == NULL) 132 return (SET_ERROR(EBADF)); 133 134 *minorp = getminor(fp->f_vnode->v_rdev); 135 ret = zfs_onexit_minor_to_state(*minorp, &zo); 136 if (ret != 0) 137 releasef(fd); 138 139 return (ret); 140 } 141 142 void 143 zfs_onexit_fd_rele(int fd) 144 { 145 releasef(fd); 146 } 147 148 /* 149 * Add a callback to be invoked when the calling process exits. 150 */ 151 int 152 zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data, 153 uint64_t *action_handle) 154 { 155 zfs_onexit_t *zo; 156 zfs_onexit_action_node_t *ap; 157 int error; 158 159 error = zfs_onexit_minor_to_state(minor, &zo); 160 if (error) 161 return (error); 162 163 ap = kmem_alloc(sizeof (zfs_onexit_action_node_t), KM_SLEEP); 164 list_link_init(&ap->za_link); 165 ap->za_func = func; 166 ap->za_data = data; 167 168 mutex_enter(&zo->zo_lock); 169 list_insert_tail(&zo->zo_actions, ap); 170 mutex_exit(&zo->zo_lock); 171 if (action_handle) 172 *action_handle = (uint64_t)(uintptr_t)ap; 173 174 return (0); 175 } 176 177 static zfs_onexit_action_node_t * 178 zfs_onexit_find_cb(zfs_onexit_t *zo, uint64_t action_handle) 179 { 180 zfs_onexit_action_node_t *match; 181 zfs_onexit_action_node_t *ap; 182 list_t *l; 183 184 ASSERT(MUTEX_HELD(&zo->zo_lock)); 185 186 match = (zfs_onexit_action_node_t *)(uintptr_t)action_handle; 187 l = &zo->zo_actions; 188 for (ap = list_head(l); ap != NULL; ap = list_next(l, ap)) { 189 if (match == ap) 190 break; 191 } 192 return (ap); 193 } 194 195 /* 196 * Delete the callback, triggering it first if 'fire' is set. 197 */ 198 int 199 zfs_onexit_del_cb(minor_t minor, uint64_t action_handle, boolean_t fire) 200 { 201 zfs_onexit_t *zo; 202 zfs_onexit_action_node_t *ap; 203 int error; 204 205 error = zfs_onexit_minor_to_state(minor, &zo); 206 if (error) 207 return (error); 208 209 mutex_enter(&zo->zo_lock); 210 ap = zfs_onexit_find_cb(zo, action_handle); 211 if (ap != NULL) { 212 list_remove(&zo->zo_actions, ap); 213 mutex_exit(&zo->zo_lock); 214 if (fire) 215 ap->za_func(ap->za_data); 216 kmem_free(ap, sizeof (zfs_onexit_action_node_t)); 217 } else { 218 mutex_exit(&zo->zo_lock); 219 error = SET_ERROR(ENOENT); 220 } 221 222 return (error); 223 } 224 225 /* 226 * Return the data associated with this callback. This allows consumers 227 * of the cleanup-on-exit interfaces to stash kernel data across system 228 * calls, knowing that it will be cleaned up if the calling process exits. 229 */ 230 int 231 zfs_onexit_cb_data(minor_t minor, uint64_t action_handle, void **data) 232 { 233 zfs_onexit_t *zo; 234 zfs_onexit_action_node_t *ap; 235 int error; 236 237 *data = NULL; 238 239 error = zfs_onexit_minor_to_state(minor, &zo); 240 if (error) 241 return (error); 242 243 mutex_enter(&zo->zo_lock); 244 ap = zfs_onexit_find_cb(zo, action_handle); 245 if (ap != NULL) 246 *data = ap->za_data; 247 else 248 error = SET_ERROR(ENOENT); 249 mutex_exit(&zo->zo_lock); 250 251 return (error); 252 } 253