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