xref: /illumos-gate/usr/src/uts/common/fs/sockfs/socknotify.c (revision a5eb7107f06a6e23e8e77e8d3a84c1ff90a73ac6)
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 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/stropts.h>
34 #include <sys/socketvar.h>
35 #include <sys/ksocket.h>
36 #include <io/ksocket/ksocket_impl.h>
37 #include <fs/sockfs/sockcommon.h>
38 #include <fs/sockfs/sodirect.h>
39 #include <fs/sockfs/sockfilter_impl.h>
40 
41 /*
42  * There can only be a single thread waiting for data (enforced by
43  * so_lock_read()), whereas for write there might be multiple threads
44  * waiting for transmit buffers. So therefore we use cv_broadcast for
45  * write and cv_signal for read.
46  */
47 #define	SO_WAKEUP_READER(so) {				\
48 	if ((so)->so_rcv_wakeup) {			\
49 		(so)->so_rcv_wakeup = B_FALSE;		\
50 		cv_signal(&(so)->so_rcv_cv);		\
51 	}						\
52 }
53 
54 #define	SO_WAKEUP_WRITER(so) {			\
55 	if ((so)->so_snd_wakeup) {		\
56 		(so)->so_snd_wakeup = B_FALSE;	\
57 		cv_broadcast(&(so)->so_snd_cv);	\
58 	}					\
59 }
60 
61 static int i_so_notify_last_rx(struct sonode *, int *, int *);
62 static int i_so_notify_last_tx(struct sonode *, int *, int *);
63 
64 /*
65  * The notification functions must be called with so_lock held,
66  * and they will all *drop* so_lock before returning.
67  */
68 
69 /*
70  * Wake up anyone waiting for the connection to be established.
71  */
72 void
so_notify_connected(struct sonode * so)73 so_notify_connected(struct sonode *so)
74 {
75 	ASSERT(MUTEX_HELD(&so->so_lock));
76 
77 	if (IS_KERNEL_SOCKET(so)) {
78 		KSOCKET_CALLBACK(so, connected, 0);
79 		mutex_exit(&so->so_lock);
80 	} else {
81 		socket_sendsig(so, SOCKETSIG_WRITE);
82 		mutex_exit(&so->so_lock);
83 		pollwakeup(&so->so_poll_list, POLLOUT);
84 	}
85 	sof_sonode_notify_filters(so, SOF_EV_CONNECTED, 0);
86 
87 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
88 }
89 
90 /*
91  * The socket is disconnecting, so no more data can be sent. Wake up
92  * anyone that is waiting to send data.
93  */
94 void
so_notify_disconnecting(struct sonode * so)95 so_notify_disconnecting(struct sonode *so)
96 {
97 	int pollev = 0;
98 	int sigev = 0;
99 
100 	ASSERT(MUTEX_HELD(&so->so_lock));
101 	(void) i_so_notify_last_tx(so, &pollev, &sigev);
102 
103 	if (IS_KERNEL_SOCKET(so)) {
104 		KSOCKET_CALLBACK(so, cantsendmore, 0);
105 		mutex_exit(&so->so_lock);
106 	} else {
107 		if (sigev != 0)
108 			socket_sendsig(so, sigev);
109 		mutex_exit(&so->so_lock);
110 
111 		if (pollev != 0)
112 			pollwakeup(&so->so_poll_list, pollev);
113 	}
114 	sof_sonode_notify_filters(so, SOF_EV_CANTSENDMORE, 0);
115 
116 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
117 }
118 
119 /*
120  * The socket is disconnected, so not more data can be sent or received.
121  * Wake up anyone that is waiting to send or receive data.
122  */
123 void
so_notify_disconnected(struct sonode * so,boolean_t connfailed,int error)124 so_notify_disconnected(struct sonode *so, boolean_t connfailed, int error)
125 {
126 	int pollev = 0;
127 	int sigev = 0;
128 
129 	ASSERT(MUTEX_HELD(&so->so_lock));
130 
131 	(void) i_so_notify_last_tx(so, &pollev, &sigev);
132 	(void) i_so_notify_last_rx(so, &pollev, &sigev);
133 
134 	if (IS_KERNEL_SOCKET(so)) {
135 		if (connfailed) {
136 			KSOCKET_CALLBACK(so, disconnected, error);
137 		} else {
138 			KSOCKET_CALLBACK(so, connectfailed, error);
139 		}
140 		mutex_exit(&so->so_lock);
141 	} else {
142 		if (sigev != 0)
143 			socket_sendsig(so, sigev);
144 		mutex_exit(&so->so_lock);
145 
146 		/*
147 		 * If we're here because the socket has become disconnected,
148 		 * we explicitly set POLLHUP.  At the same time, we also clear
149 		 * POLLOUT, as POLLOUT and POLLHUP are defined to be mutually
150 		 * exclusive with respect to one another.
151 		 */
152 		if (!connfailed)
153 			pollev = (pollev | POLLHUP) & ~POLLOUT;
154 
155 		if (pollev != 0)
156 			pollwakeup(&so->so_poll_list, pollev);
157 	}
158 	sof_sonode_notify_filters(so, (connfailed) ? SOF_EV_CONNECTFAILED :
159 	    SOF_EV_DISCONNECTED, error);
160 
161 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
162 }
163 
164 /*
165  * The socket is writeable. Wake up anyone waiting to send data.
166  */
167 void
so_notify_writable(struct sonode * so)168 so_notify_writable(struct sonode *so)
169 {
170 	ASSERT(MUTEX_HELD(&so->so_lock));
171 
172 	SO_WAKEUP_WRITER(so);
173 
174 	if (IS_KERNEL_SOCKET(so)) {
175 		KSOCKET_CALLBACK(so, cansend, 0);
176 		mutex_exit(&so->so_lock);
177 	} else {
178 		socket_sendsig(so, SOCKETSIG_WRITE);
179 		mutex_exit(&so->so_lock);
180 		pollwakeup(&so->so_poll_list, POLLOUT);
181 	}
182 
183 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
184 
185 	/* filters can start injecting data */
186 	if (so->so_filter_active > 0)
187 		sof_sonode_notify_filters(so, SOF_EV_INJECT_DATA_OUT_OK, 0);
188 }
189 
190 /*
191  * Data is available, so wake up anyone waiting for data.
192  */
193 void
so_notify_data(struct sonode * so,size_t qlen)194 so_notify_data(struct sonode *so, size_t qlen)
195 {
196 	ASSERT(MUTEX_HELD(&so->so_lock));
197 
198 	SO_WAKEUP_READER(so);
199 
200 	if (IS_KERNEL_SOCKET(so)) {
201 		KSOCKET_CALLBACK(so, newdata, qlen);
202 		mutex_exit(&so->so_lock);
203 	} else {
204 		socket_sendsig(so, SOCKETSIG_READ);
205 		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
206 			so->so_pollev &= ~SO_POLLEV_IN;
207 			mutex_exit(&so->so_lock);
208 			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
209 		} else {
210 			mutex_exit(&so->so_lock);
211 		}
212 	}
213 
214 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
215 }
216 
217 /*
218  * Transient error. Wake up anyone waiting to send or receive data.
219  */
220 void
so_notify_error(struct sonode * so)221 so_notify_error(struct sonode *so)
222 {
223 	ASSERT(MUTEX_HELD(&so->so_lock));
224 
225 	SO_WAKEUP_WRITER(so);
226 	SO_WAKEUP_READER(so);
227 
228 	if (IS_KERNEL_SOCKET(so)) {
229 		KSOCKET_CALLBACK(so, error, 0);
230 		mutex_exit(&so->so_lock);
231 	} else {
232 		socket_sendsig(so, SOCKETSIG_WRITE|SOCKETSIG_READ);
233 		so->so_pollev &= ~SO_POLLEV_IN;
234 		mutex_exit(&so->so_lock);
235 		pollwakeup(&so->so_poll_list, POLLOUT|POLLIN|POLLRDNORM);
236 	}
237 
238 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
239 }
240 
241 /*
242  * Out-of-band data is incoming, notify any interested parties.
243  */
244 void
so_notify_oobsig(struct sonode * so)245 so_notify_oobsig(struct sonode *so)
246 {
247 	socket_sendsig(so, SOCKETSIG_URG);
248 	mutex_exit(&so->so_lock);
249 	pollwakeup(&so->so_poll_list, POLLRDBAND);
250 }
251 
252 /*
253  * Received out-of-band data. If the OOB data is delivered inline, then
254  * in addition of regular OOB notification, anyone waiting for normal
255  * data is also notified.
256  */
257 void
so_notify_oobdata(struct sonode * so,boolean_t oob_inline)258 so_notify_oobdata(struct sonode *so, boolean_t oob_inline)
259 {
260 	ASSERT(MUTEX_HELD(&so->so_lock));
261 	if (so->so_direct != NULL)
262 		SOD_UIOAFINI(so->so_direct);
263 
264 	SO_WAKEUP_READER(so);
265 
266 	if (IS_KERNEL_SOCKET(so)) {
267 		KSOCKET_CALLBACK(so, oobdata, 0);
268 		mutex_exit(&so->so_lock);
269 	} else {
270 		if (oob_inline) {
271 			socket_sendsig(so, SOCKETSIG_READ);
272 			so->so_pollev &= ~SO_POLLEV_IN;
273 			mutex_exit(&so->so_lock);
274 			pollwakeup(&so->so_poll_list,
275 			    POLLRDBAND|POLLIN|POLLRDNORM);
276 		} else {
277 			mutex_exit(&so->so_lock);
278 			pollwakeup(&so->so_poll_list, POLLRDBAND);
279 		}
280 	}
281 
282 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
283 }
284 
285 /*
286  * End-of-file has been reach, so peer will send no new data. Wake up
287  * anyone that is waiting for data.
288  */
289 void
so_notify_eof(struct sonode * so)290 so_notify_eof(struct sonode *so)
291 {
292 	int pollev = 0;
293 	int sigev = 0;
294 
295 	ASSERT(MUTEX_HELD(&so->so_lock));
296 
297 	(void) i_so_notify_last_rx(so, &pollev, &sigev);
298 
299 	if (IS_KERNEL_SOCKET(so)) {
300 		KSOCKET_CALLBACK(so, cantrecvmore, 0);
301 		mutex_exit(&so->so_lock);
302 	} else {
303 		if (sigev != 0)
304 			socket_sendsig(so, sigev);
305 		mutex_exit(&so->so_lock);
306 		if (pollev != 0)
307 			pollwakeup(&so->so_poll_list, pollev);
308 
309 	}
310 	sof_sonode_notify_filters(so, SOF_EV_CANTRECVMORE, 0);
311 
312 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
313 }
314 
315 /*
316  * Wake up anyone waiting for a new connection.
317  */
318 void
so_notify_newconn(struct sonode * so)319 so_notify_newconn(struct sonode *so)
320 {
321 	ASSERT(MUTEX_HELD(&so->so_lock));
322 
323 	if (IS_KERNEL_SOCKET(so)) {
324 		KSOCKET_CALLBACK(so, newconn, 0);
325 		mutex_exit(&so->so_lock);
326 	} else {
327 		socket_sendsig(so, SOCKETSIG_READ);
328 		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
329 			so->so_pollev &= ~SO_POLLEV_IN;
330 			mutex_exit(&so->so_lock);
331 			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
332 		} else {
333 			mutex_exit(&so->so_lock);
334 		}
335 	}
336 
337 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
338 }
339 
340 /*
341  * User initated shutdown/close, wake anyone that is trying to do
342  * an operation that is no longer possible.
343  */
344 void
so_notify_shutdown(struct sonode * so)345 so_notify_shutdown(struct sonode *so)
346 {
347 	int pollev = 0;
348 	int sigev = 0;
349 
350 	ASSERT(MUTEX_HELD(&so->so_lock));
351 	ASSERT(so->so_state & (SS_CANTSENDMORE|SS_CANTRCVMORE));
352 
353 	if (so->so_state & SS_CANTSENDMORE)
354 		(void) i_so_notify_last_tx(so, &pollev, &sigev);
355 	if (so->so_state & SS_CANTRCVMORE)
356 		(void) i_so_notify_last_rx(so, &pollev, &sigev);
357 
358 	if (sigev != 0)
359 		socket_sendsig(so, sigev);
360 	mutex_exit(&so->so_lock);
361 	if (pollev != 0)
362 		pollwakeup(&so->so_poll_list, pollev);
363 
364 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
365 }
366 
367 /*
368  * No more data will be coming in, and this will be the last notification
369  * made.
370  */
371 static int
i_so_notify_last_rx(struct sonode * so,int * pollev,int * sigev)372 i_so_notify_last_rx(struct sonode *so, int *pollev, int *sigev)
373 {
374 	if (!(so->so_state & SS_SENTLASTREADSIG)) {
375 		SOCKET_TIMER_CANCEL(so);
376 		SO_WAKEUP_READER(so);
377 		so->so_state |= SS_SENTLASTREADSIG;
378 		so->so_pollev &= ~SO_POLLEV_IN;
379 
380 		*pollev |= POLLIN|POLLRDNORM|POLLRDHUP;
381 		*sigev |= SOCKETSIG_READ;
382 
383 		return (1);
384 	} else {
385 		return (0);
386 	}
387 }
388 
389 /*
390  * The socket is un-writeable. Make one last notification.
391  */
392 static int
i_so_notify_last_tx(struct sonode * so,int * pollev,int * sigev)393 i_so_notify_last_tx(struct sonode *so, int *pollev, int *sigev)
394 {
395 	if (!(so->so_state & SS_SENTLASTWRITESIG)) {
396 		SO_WAKEUP_WRITER(so);
397 		so->so_state |= SS_SENTLASTWRITESIG;
398 
399 		*pollev |= POLLOUT;
400 		*sigev |= SOCKETSIG_WRITE;
401 
402 		return (1);
403 	} else {
404 		return (0);
405 	}
406 }
407