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