1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2013, 2020 by Delphix. All rights reserved. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/param.h> 29 #include <sys/errno.h> 30 #include <sys/kmem.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 * simply by opening ZFS_DEV. This causes the ZFS driver to do create 44 * some private data for the file descriptor and generating a unique 45 * minor number. The process then passes along that file descriptor to 46 * each ioctl that might have a cleanup operation. 47 * 48 * Consumers of the onexit routines should call zfs_onexit_fd_hold() early 49 * on to validate the given fd and add a reference to its file table entry. 50 * This allows the consumer to do its work and then add a callback, knowing 51 * that zfs_onexit_add_cb() won't fail with EBADF. When finished, consumers 52 * should call zfs_onexit_fd_rele(). 53 * 54 * A simple example is zfs_ioc_recv(), where we might create an AVL tree 55 * with dataset/GUID mappings and then reuse that tree on subsequent 56 * zfs_ioc_recv() calls. 57 * 58 * On the first zfs_ioc_recv() call, dmu_recv_stream() will kmem_alloc() 59 * the AVL tree and pass it along with a callback function to 60 * zfs_onexit_add_cb(). The zfs_onexit_add_cb() routine will register the 61 * callback and return an action handle. 62 * 63 * The action handle is then passed from user space to subsequent 64 * zfs_ioc_recv() calls, so that dmu_recv_stream() can fetch its AVL tree 65 * by calling zfs_onexit_cb_data() with the device minor number and 66 * action handle. 67 * 68 * If the user process exits abnormally, the callback is invoked implicitly 69 * as part of the driver close operation. Once the user space process is 70 * finished with the accumulated kernel state, it can also just call close(2) 71 * on the cleanup fd to trigger the cleanup callback. 72 */ 73 74 void 75 zfs_onexit_init(zfs_onexit_t **zop) 76 { 77 zfs_onexit_t *zo; 78 79 zo = *zop = kmem_zalloc(sizeof (zfs_onexit_t), KM_SLEEP); 80 mutex_init(&zo->zo_lock, NULL, MUTEX_DEFAULT, NULL); 81 list_create(&zo->zo_actions, sizeof (zfs_onexit_action_node_t), 82 offsetof(zfs_onexit_action_node_t, za_link)); 83 } 84 85 void 86 zfs_onexit_destroy(zfs_onexit_t *zo) 87 { 88 zfs_onexit_action_node_t *ap; 89 90 mutex_enter(&zo->zo_lock); 91 while ((ap = list_remove_head(&zo->zo_actions)) != NULL) { 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 /* 105 * Consumers might need to operate by minor number instead of fd, since 106 * they might be running in another thread (e.g. txg_sync_thread). Callers 107 * of this function must call zfs_onexit_fd_rele() when they're finished 108 * using the minor number. 109 */ 110 zfs_file_t * 111 zfs_onexit_fd_hold(int fd, minor_t *minorp) 112 { 113 zfs_onexit_t *zo = NULL; 114 115 zfs_file_t *fp = zfs_file_get(fd); 116 if (fp == NULL) 117 return (NULL); 118 119 int error = zfsdev_getminor(fp, minorp); 120 if (error) { 121 zfs_onexit_fd_rele(fp); 122 return (NULL); 123 } 124 125 zo = zfsdev_get_state(*minorp, ZST_ONEXIT); 126 if (zo == NULL) { 127 zfs_onexit_fd_rele(fp); 128 return (NULL); 129 } 130 return (fp); 131 } 132 133 void 134 zfs_onexit_fd_rele(zfs_file_t *fp) 135 { 136 zfs_file_put(fp); 137 } 138 139 static int 140 zfs_onexit_minor_to_state(minor_t minor, zfs_onexit_t **zo) 141 { 142 *zo = zfsdev_get_state(minor, ZST_ONEXIT); 143 if (*zo == NULL) 144 return (SET_ERROR(EBADF)); 145 146 return (0); 147 } 148 149 /* 150 * Add a callback to be invoked when the calling process exits. 151 */ 152 int 153 zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data, 154 uintptr_t *action_handle) 155 { 156 zfs_onexit_t *zo; 157 zfs_onexit_action_node_t *ap; 158 int error; 159 160 error = zfs_onexit_minor_to_state(minor, &zo); 161 if (error) 162 return (error); 163 164 ap = kmem_alloc(sizeof (zfs_onexit_action_node_t), KM_SLEEP); 165 list_link_init(&ap->za_link); 166 ap->za_func = func; 167 ap->za_data = data; 168 169 mutex_enter(&zo->zo_lock); 170 list_insert_tail(&zo->zo_actions, ap); 171 mutex_exit(&zo->zo_lock); 172 if (action_handle) 173 *action_handle = (uintptr_t)ap; 174 175 return (0); 176 } 177