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