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 /* 26 * Copyright (c) 2006 Oracle. All rights reserved. 27 * 28 * This software is available to you under a choice of one of two 29 * licenses. You may choose to be licensed under the terms of the GNU 30 * General Public License (GPL) Version 2, available from the file 31 * COPYING in the main directory of this source tree, or the 32 * OpenIB.org BSD license below: 33 * 34 * Redistribution and use in source and binary forms, with or 35 * without modification, are permitted provided that the following 36 * conditions are met: 37 * 38 * - Redistributions of source code must retain the above 39 * copyright notice, this list of conditions and the following 40 * disclaimer. 41 * 42 * - Redistributions in binary form must reproduce the above 43 * copyright notice, this list of conditions and the following 44 * disclaimer in the documentation and/or other materials 45 * provided with the distribution. 46 * 47 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 48 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 49 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 50 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 51 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 52 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 53 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 54 * SOFTWARE. 55 * 56 */ 57 #include <sys/rds.h> 58 59 #include <sys/ib/clients/rdsv3/rdsv3.h> 60 #include <sys/ib/clients/rdsv3/rdsv3_debug.h> 61 62 /* 63 * This file implements a getsockopt() call which copies a set of fixed 64 * sized structs into a user-specified buffer as a means of providing 65 * read-only information about RDS. 66 * 67 * For a given information source there are a given number of fixed sized 68 * structs at a given time. The structs are only copied if the user-specified 69 * buffer is big enough. The destination pages that make up the buffer 70 * are pinned for the duration of the copy. 71 * 72 * This gives us the following benefits: 73 * 74 * - simple implementation, no copy "position" across multiple calls 75 * - consistent snapshot of an info source 76 * - atomic copy works well with whatever locking info source has 77 * - one portable tool to get rds info across implementations 78 * - long-lived tool can get info without allocating 79 * 80 * at the following costs: 81 * 82 * - info source copy must be pinned, may be "large" 83 */ 84 85 static kmutex_t rdsv3_info_lock; 86 static rdsv3_info_func rdsv3_info_funcs[RDSV3_INFO_LAST - RDSV3_INFO_FIRST + 1]; 87 88 void 89 rdsv3_info_register_func(int optname, rdsv3_info_func func) 90 { 91 int offset = optname - RDSV3_INFO_FIRST; 92 93 ASSERT(optname >= RDSV3_INFO_FIRST && optname <= RDSV3_INFO_LAST); 94 95 mutex_enter(&rdsv3_info_lock); 96 ASSERT(!rdsv3_info_funcs[offset]); 97 rdsv3_info_funcs[offset] = func; 98 mutex_exit(&rdsv3_info_lock); 99 } 100 101 /* ARGSUSED */ 102 void 103 rdsv3_info_deregister_func(int optname, rdsv3_info_func func) 104 { 105 int offset = optname - RDSV3_INFO_FIRST; 106 107 ASSERT(optname >= RDSV3_INFO_FIRST && optname <= RDSV3_INFO_LAST); 108 109 mutex_enter(&rdsv3_info_lock); 110 rdsv3_info_funcs[offset] = NULL; 111 mutex_exit(&rdsv3_info_lock); 112 } 113 114 /* 115 * @optval points to the userspace buffer that the information snapshot 116 * will be copied into. 117 * 118 * This function returns -errno if there is a failure, particularly -ENOSPC 119 * if the given userspace buffer was not large enough to fit the snapshot. 120 * On success it returns the positive number of bytes of each array element 121 * in the snapshot. 122 */ 123 int 124 rdsv3_info_ioctl(struct rsock *sock, int optname, char *optval, 125 int32_t *rvalp) 126 { 127 struct rdsv3_info_iterator iter; 128 struct rdsv3_info_lengths lens; 129 rdsv3_info_func func; 130 struct rds_info_arg arg; 131 uint32_t ulen = 0, klen; 132 133 func = rdsv3_info_funcs[optname - RDSV3_INFO_FIRST]; 134 if (func == NULL) { 135 RDSV3_DPRINTF2("rdsv3_info_ioctl", 136 "No Info Function, optname: %d", optname); 137 return (ENOPROTOOPT); 138 } 139 140 if (optval == NULL) { 141 RDSV3_DPRINTF2("rdsv3_info_ioctl", "optval is NULL"); 142 return (EINVAL); 143 } 144 if (ddi_copyin(optval, &arg, sizeof (struct rds_info_arg), 0) != 0) { 145 RDSV3_DPRINTF2("rdsv3_info_ioctl", 146 "ddi_copyin for address: 0x%p failed", optval); 147 return (EFAULT); 148 } 149 150 RDSV3_DPRINTF4("rdsv3_info_ioctl", 151 "optname: %d lenp: %llx datap: %llx", optname, arg.lenp, arg.datap); 152 153 if (arg.lenp == NULL) { 154 RDSV3_DPRINTF2("rdsv3_info_ioctl", "arg.lenp is NULL"); 155 return (EFAULT); 156 } 157 158 if (ddi_copyin((void *)(uintptr_t)arg.lenp, &ulen, 159 sizeof (uint32_t), 0) != 0) { 160 RDSV3_DPRINTF2("rdsv3_info_ioctl", 161 "ddi_copyin for address, lenp: 0x%p failed", arg.lenp); 162 return (EFAULT); 163 } 164 165 RDSV3_DPRINTF3("rdsv3_info_ioctl", "optname: %d len: %d datap: %p", 166 optname, ulen, arg.datap); 167 168 bzero(&iter, sizeof (struct rdsv3_info_iterator)); 169 /* a 0 len call is just trying to probe its length */ 170 if (ulen == 0) { 171 iter.addr = NULL; 172 } else if (arg.datap == NULL) { 173 RDSV3_DPRINTF2("rdsv3_info_ioctl", 174 "arg.datap is NULL, ulen set to: %d", ulen); 175 return (EINVAL); 176 } else { 177 iter.addr = (char *)(uintptr_t)arg.datap; 178 } 179 iter.offset = 0; 180 181 bzero(&lens, sizeof (struct rdsv3_info_lengths)); 182 func(sock, ulen, &iter, &lens); 183 184 klen = lens.nr * lens.each; 185 186 if (ddi_copyout(&klen, (void *)(uintptr_t)arg.lenp, 187 sizeof (uint32_t), 0) != 0) { 188 RDSV3_DPRINTF2("rdsv3_info_ioctl", 189 "ddi_copyout(%p %p) failed", &klen, arg.lenp); 190 return (EFAULT); 191 } 192 193 RDSV3_DPRINTF3("rdsv3_info_ioctl", 194 "optname: %d ulen: %d klen: %d each: %d", optname, ulen, klen, 195 lens.each); 196 197 if (ulen < klen) { 198 return (ENOSPC); 199 } 200 201 RDSV3_DPRINTF4("rdsv3_info_ioctl", "Return optname: %d", optname); 202 203 *rvalp = lens.each; 204 return (0); 205 } 206