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