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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
26 */
27
28
29 /*
30 * Overview of the RSM Kernel Agent:
31 * ---------------------------------
32 *
33 * rsm.c constitutes the implementation of the RSM kernel agent. The RSM
34 * kernel agent is a pseudo device driver which makes use of the RSMPI
35 * interface on behalf of the RSMAPI user library.
36 *
37 * The kernel agent functionality can be categorized into the following
38 * components:
39 * 1. Driver Infrastructure
40 * 2. Export/Import Segment Management
41 * 3. Internal resource allocation/deallocation
42 *
43 * The driver infrastructure includes the basic module loading entry points
44 * like _init, _info, _fini to load, unload and report information about
45 * the driver module. The driver infrastructure also includes the
2402 rsmka_release_adapter(adapter);
2403 e = RSMERR_BAD_ADDR;
2404 }
2405 }
2406 #endif
2407 if (ddi_copyout((caddr_t)&msg->rnum,
2408 (caddr_t)&((rsm_ioctlmsg_t *)dataptr)->rnum,
2409 sizeof (minor_t), mode)) {
2410 rsmka_release_adapter(adapter);
2411 e = RSMERR_BAD_ADDR;
2412 }
2413 }
2414
2415 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind done\n"));
2416
2417 return (e);
2418 }
2419
2420 static void
2421 rsm_remap_local_importers(rsm_node_id_t src_nodeid,
2422 rsm_memseg_id_t ex_segid,
2423 ddi_umem_cookie_t cookie)
2424
2425 {
2426 rsmresource_t *p = NULL;
2427 rsmhash_table_t *rhash = &rsm_import_segs;
2428 uint_t index;
2429
2430 DBG_PRINTF((RSM_KERNEL_AGENT | RSM_FUNC_ALL, RSM_DEBUG_VERBOSE,
2431 "rsm_remap_local_importers enter\n"));
2432
2433 index = rsmhash(ex_segid);
2434
2435 rw_enter(&rhash->rsmhash_rw, RW_READER);
2436
2437 p = rsmhash_getbkt(rhash, index);
2438
2439 for (; p; p = p->rsmrc_next) {
2440 rsmseg_t *seg = (rsmseg_t *)p;
2441 rsmseglock_acquire(seg);
2442 /*
2443 * Change the s_cookie value of only the local importers
2444 * which have been mapped (in state RSM_STATE_ACTIVE).
3627 reply.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPLY;
3628 reply.rsmipc_hdr.rsmipc_cookie = req->rsmipc_hdr.rsmipc_cookie;
3629
3630 (void) rsmipc_send(src, NULL, &reply);
3631
3632 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3633 "rsm_intr_segconnect done\n"));
3634 }
3635
3636
3637 /*
3638 * When an exported segment is unpublished the exporter sends an ipc
3639 * message (RSMIPC_MSG_DISCONNECT) to all importers. The recv ipc dispatcher
3640 * calls this function. The import list is scanned; segments which match the
3641 * exported segment id are unloaded and disconnected.
3642 *
3643 * Will also be called from rsm_rebind with disconnect_flag FALSE.
3644 *
3645 */
3646 static void
3647 rsm_force_unload(rsm_node_id_t src_nodeid,
3648 rsm_memseg_id_t ex_segid,
3649 boolean_t disconnect_flag)
3650
3651 {
3652 rsmresource_t *p = NULL;
3653 rsmhash_table_t *rhash = &rsm_import_segs;
3654 uint_t index;
3655 DBG_DEFINE(category,
3656 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
3657
3658 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_force_unload enter\n"));
3659
3660 index = rsmhash(ex_segid);
3661
3662 rw_enter(&rhash->rsmhash_rw, RW_READER);
3663
3664 p = rsmhash_getbkt(rhash, index);
3665
3666 for (; p; p = p->rsmrc_next) {
3667 rsmseg_t *seg = (rsmseg_t *)p;
3668 if ((seg->s_segid == ex_segid) && (seg->s_node == src_nodeid)) {
3669 /*
3670 * In order to make rsmseg_unload and rsm_force_unload
6745
6746 if (shared_cookie != NULL) {
6747 /*
6748 * This is the last importer so inform the exporting node
6749 * so this import can be deleted from the list of importers.
6750 */
6751 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_NOTIMPORTING;
6752 request.rsmipc_key = seg->s_segid;
6753 request.rsmipc_segment_cookie = shared_cookie;
6754 rsmseglock_release(seg);
6755 (void) rsmipc_send(seg->s_node, &request, RSM_NO_REPLY);
6756 } else {
6757 rsmseglock_release(seg);
6758 }
6759
6760 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_disconnect done\n"));
6761
6762 return (DDI_SUCCESS);
6763 }
6764
6765 /*ARGSUSED*/
6766 static int
6767 rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
6768 struct pollhead **phpp)
6769 {
6770 minor_t rnum;
6771 rsmresource_t *res;
6772 rsmseg_t *seg;
6773 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
6774
6775 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_chpoll enter\n"));
6776
6777 /* find minor, no lock */
6778 rnum = getminor(dev);
6779 res = rsmresource_lookup(rnum, RSM_NOLOCK);
6780
6781 /* poll is supported only for export/import segments */
6782 if ((res == NULL) || (res == RSMRC_RESERVED) ||
6783 (res->rsmrc_type == RSM_RESOURCE_BAR)) {
6784 return (ENXIO);
6785 }
6786
6787 *reventsp = 0;
6788
6789 /*
6790 * An exported segment must be in state RSM_STATE_EXPORT; an
6791 * imported segment must be in state RSM_STATE_ACTIVE.
6792 */
6793 seg = (rsmseg_t *)res;
6794
6795 if (seg->s_pollevent) {
6796 *reventsp = POLLRDNORM;
6797 } else if (!anyyet) {
6798 /* cannot take segment lock here */
6799 *phpp = &seg->s_poll;
6800 seg->s_pollflag |= RSM_SEGMENT_POLL;
6801 }
6802 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_chpoll done\n"));
6803 return (0);
6804 }
6805
6806
6807
6808 /* ************************* IOCTL Commands ********************* */
6809
6810 static rsmseg_t *
6811 rsmresource_seg(rsmresource_t *res, minor_t rnum, cred_t *credp,
6812 rsm_resource_type_t type)
6813 {
6814 /* get segment from resource handle */
6815 rsmseg_t *seg;
6816 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
6817
|
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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
26 * Copyright 2017 Joyent, Inc.
27 */
28
29
30 /*
31 * Overview of the RSM Kernel Agent:
32 * ---------------------------------
33 *
34 * rsm.c constitutes the implementation of the RSM kernel agent. The RSM
35 * kernel agent is a pseudo device driver which makes use of the RSMPI
36 * interface on behalf of the RSMAPI user library.
37 *
38 * The kernel agent functionality can be categorized into the following
39 * components:
40 * 1. Driver Infrastructure
41 * 2. Export/Import Segment Management
42 * 3. Internal resource allocation/deallocation
43 *
44 * The driver infrastructure includes the basic module loading entry points
45 * like _init, _info, _fini to load, unload and report information about
46 * the driver module. The driver infrastructure also includes the
2403 rsmka_release_adapter(adapter);
2404 e = RSMERR_BAD_ADDR;
2405 }
2406 }
2407 #endif
2408 if (ddi_copyout((caddr_t)&msg->rnum,
2409 (caddr_t)&((rsm_ioctlmsg_t *)dataptr)->rnum,
2410 sizeof (minor_t), mode)) {
2411 rsmka_release_adapter(adapter);
2412 e = RSMERR_BAD_ADDR;
2413 }
2414 }
2415
2416 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_bind done\n"));
2417
2418 return (e);
2419 }
2420
2421 static void
2422 rsm_remap_local_importers(rsm_node_id_t src_nodeid,
2423 rsm_memseg_id_t ex_segid, ddi_umem_cookie_t cookie)
2424 {
2425 rsmresource_t *p = NULL;
2426 rsmhash_table_t *rhash = &rsm_import_segs;
2427 uint_t index;
2428
2429 DBG_PRINTF((RSM_KERNEL_AGENT | RSM_FUNC_ALL, RSM_DEBUG_VERBOSE,
2430 "rsm_remap_local_importers enter\n"));
2431
2432 index = rsmhash(ex_segid);
2433
2434 rw_enter(&rhash->rsmhash_rw, RW_READER);
2435
2436 p = rsmhash_getbkt(rhash, index);
2437
2438 for (; p; p = p->rsmrc_next) {
2439 rsmseg_t *seg = (rsmseg_t *)p;
2440 rsmseglock_acquire(seg);
2441 /*
2442 * Change the s_cookie value of only the local importers
2443 * which have been mapped (in state RSM_STATE_ACTIVE).
3626 reply.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_REPLY;
3627 reply.rsmipc_hdr.rsmipc_cookie = req->rsmipc_hdr.rsmipc_cookie;
3628
3629 (void) rsmipc_send(src, NULL, &reply);
3630
3631 DBG_PRINTF((category, RSM_DEBUG_VERBOSE,
3632 "rsm_intr_segconnect done\n"));
3633 }
3634
3635
3636 /*
3637 * When an exported segment is unpublished the exporter sends an ipc
3638 * message (RSMIPC_MSG_DISCONNECT) to all importers. The recv ipc dispatcher
3639 * calls this function. The import list is scanned; segments which match the
3640 * exported segment id are unloaded and disconnected.
3641 *
3642 * Will also be called from rsm_rebind with disconnect_flag FALSE.
3643 *
3644 */
3645 static void
3646 rsm_force_unload(rsm_node_id_t src_nodeid, rsm_memseg_id_t ex_segid,
3647 boolean_t disconnect_flag)
3648 {
3649 rsmresource_t *p = NULL;
3650 rsmhash_table_t *rhash = &rsm_import_segs;
3651 uint_t index;
3652 DBG_DEFINE(category,
3653 RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_INTR_CALLBACK);
3654
3655 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_force_unload enter\n"));
3656
3657 index = rsmhash(ex_segid);
3658
3659 rw_enter(&rhash->rsmhash_rw, RW_READER);
3660
3661 p = rsmhash_getbkt(rhash, index);
3662
3663 for (; p; p = p->rsmrc_next) {
3664 rsmseg_t *seg = (rsmseg_t *)p;
3665 if ((seg->s_segid == ex_segid) && (seg->s_node == src_nodeid)) {
3666 /*
3667 * In order to make rsmseg_unload and rsm_force_unload
6742
6743 if (shared_cookie != NULL) {
6744 /*
6745 * This is the last importer so inform the exporting node
6746 * so this import can be deleted from the list of importers.
6747 */
6748 request.rsmipc_hdr.rsmipc_type = RSMIPC_MSG_NOTIMPORTING;
6749 request.rsmipc_key = seg->s_segid;
6750 request.rsmipc_segment_cookie = shared_cookie;
6751 rsmseglock_release(seg);
6752 (void) rsmipc_send(seg->s_node, &request, RSM_NO_REPLY);
6753 } else {
6754 rsmseglock_release(seg);
6755 }
6756
6757 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_disconnect done\n"));
6758
6759 return (DDI_SUCCESS);
6760 }
6761
6762 static int
6763 rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
6764 struct pollhead **phpp)
6765 {
6766 minor_t rnum;
6767 rsmresource_t *res;
6768 rsmseg_t *seg;
6769 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_DDI);
6770
6771 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_chpoll enter\n"));
6772
6773 /* find minor, no lock */
6774 rnum = getminor(dev);
6775 res = rsmresource_lookup(rnum, RSM_NOLOCK);
6776
6777 /* poll is supported only for export/import segments */
6778 if ((res == NULL) || (res == RSMRC_RESERVED) ||
6779 (res->rsmrc_type == RSM_RESOURCE_BAR)) {
6780 return (ENXIO);
6781 }
6782
6783 /*
6784 * An exported segment must be in state RSM_STATE_EXPORT; an
6785 * imported segment must be in state RSM_STATE_ACTIVE.
6786 */
6787 seg = (rsmseg_t *)res;
6788
6789 if (seg->s_pollevent) {
6790 *reventsp = POLLRDNORM;
6791 } else {
6792 *reventsp = 0;
6793 }
6794
6795 if ((*reventsp == 0 && !anyyet) || (events & POLLET)) {
6796 /* cannot take segment lock here */
6797 *phpp = &seg->s_poll;
6798 seg->s_pollflag |= RSM_SEGMENT_POLL;
6799 }
6800 DBG_PRINTF((category, RSM_DEBUG_VERBOSE, "rsm_chpoll done\n"));
6801 return (0);
6802 }
6803
6804
6805
6806 /* ************************* IOCTL Commands ********************* */
6807
6808 static rsmseg_t *
6809 rsmresource_seg(rsmresource_t *res, minor_t rnum, cred_t *credp,
6810 rsm_resource_type_t type)
6811 {
6812 /* get segment from resource handle */
6813 rsmseg_t *seg;
6814 DBG_DEFINE(category, RSM_KERNEL_AGENT | RSM_FUNC_ALL | RSM_IOCTL);
6815
|