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