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 
61 /*
62  * This file implements a getsockopt() call which copies a set of fixed
63  * sized structs into a user-specified buffer as a means of providing
64  * read-only information about RDS.
65  *
66  * For a given information source there are a given number of fixed sized
67  * structs at a given time.  The structs are only copied if the user-specified
68  * buffer is big enough.  The destination pages that make up the buffer
69  * are pinned for the duration of the copy.
70  *
71  * This gives us the following benefits:
72  *
73  * - simple implementation, no copy "position" across multiple calls
74  * - consistent snapshot of an info source
75  * - atomic copy works well with whatever locking info source has
76  * - one portable tool to get rds info across implementations
77  * - long-lived tool can get info without allocating
78  *
79  * at the following costs:
80  *
81  * - info source copy must be pinned, may be "large"
82  */
83 
84 static kmutex_t rdsv3_info_lock;
85 static rdsv3_info_func rdsv3_info_funcs[RDSV3_INFO_LAST - RDSV3_INFO_FIRST + 1];
86 
87 void
88 rdsv3_info_register_func(int optname, rdsv3_info_func func)
89 {
90 	int offset = optname - RDSV3_INFO_FIRST;
91 
92 	ASSERT(optname >= RDSV3_INFO_FIRST && optname <= RDSV3_INFO_LAST);
93 
94 	mutex_enter(&rdsv3_info_lock);
95 	rdsv3_info_funcs[offset] = func;
96 	mutex_exit(&rdsv3_info_lock);
97 }
98 
99 /* ARGSUSED */
100 void
101 rdsv3_info_deregister_func(int optname, rdsv3_info_func func)
102 {
103 	int offset = optname - RDSV3_INFO_FIRST;
104 
105 	ASSERT(optname >= RDSV3_INFO_FIRST && optname <= RDSV3_INFO_LAST);
106 
107 	mutex_enter(&rdsv3_info_lock);
108 	rdsv3_info_funcs[offset] = NULL;
109 	mutex_exit(&rdsv3_info_lock);
110 }
111 
112 /*
113  * @optval points to the userspace buffer that the information snapshot
114  * will be copied into.
115  *
116  * @optlen on input is the size of the buffer in userspace.  @optlen
117  * on output is the size of the requested snapshot in bytes.
118  *
119  * This function returns -errno if there is a failure, particularly -ENOSPC
120  * if the given userspace buffer was not large enough to fit the snapshot.
121  * On success it returns the positive number of bytes of each array element
122  * in the snapshot.
123  */
124 int
125 rdsv3_info_getsockopt(struct rsock *sock, int optname, char *optval,
126     socklen_t *optlen)
127 {
128 	struct rdsv3_info_iterator iter;
129 	struct rdsv3_info_lengths lens;
130 	rdsv3_info_func func;
131 
132 	func = rdsv3_info_funcs[optname - RDSV3_INFO_FIRST];
133 	if (func == NULL) {
134 		return (-ENOPROTOOPT);
135 	}
136 
137 	if (*optlen == sizeof (struct rdsv3_info_lengths)) {
138 		iter.addr = NULL;
139 	} else {
140 		iter.addr = optval;
141 	}
142 
143 	iter.offset = 0;
144 
145 	func(sock, *optlen, &iter, &lens);
146 	ASSERT(lens.each != 0);
147 
148 	if (iter.addr == NULL) {
149 		bcopy(&lens, optval, sizeof (struct rdsv3_info_lengths));
150 	} else {
151 		*optlen = lens.nr * lens.each;
152 	}
153 
154 	return (0);
155 }
156