Whamcloud - gitweb
Landing b_hd_newconfig on HEAD
[fs/lustre-release.git] / lnet / klnds / socklnd / socklnd_lib-darwin.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002 Cluster File Systems, Inc.
5  * Author: Phil Schwan <phil@clusterfs.com>
6  *
7  * This file is part of Lustre, http://www.lustre.org.
8  *
9  * Lustre is free software; you can redistribute it and/or
10  * modify it under the terms of version 2 of the GNU General Public
11  * License as published by the Free Software Foundation.
12  *
13  * Lustre is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Lustre; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * Darwin porting library
23  * Make things easy to port
24  */
25 #include <mach/mach_types.h>
26 #include <string.h>
27 #include <netinet/in.h>
28 #include <netinet/tcp.h>
29 #include <sys/file.h>
30
31 #include "socklnd.h"
32
33 # if CONFIG_SYSCTL && !CFS_SYSFS_MODULE_PARM
34
35 SYSCTL_DECL(_lnet);
36
37 SYSCTL_NODE (_lnet,           OID_AUTO,         ksocknal,        CTLFLAG_RW, 
38              0,                                 "ksocknal_sysctl");
39
40 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         timeout, 
41            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_timeout, 
42            0,                                   "timeout");
43 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         credits, 
44            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_credits, 
45            0,                                   "credits");
46 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         peer_credits, 
47            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_peercredits, 
48            0,                                   "peer_credits");
49 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         nconnds, 
50            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_nconnds, 
51            0,                                   "nconnds");
52 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         min_reconnectms, 
53            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_min_reconnectms, 
54            0,                                   "min_reconnectms");
55 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         max_reconnectms, 
56            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_max_reconnectms, 
57            0,                                   "max_reconnectms");
58 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         eager_ack, 
59            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_eager_ack, 
60            0,                                   "eager_ack");
61 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         typed, 
62            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_typed_conns, 
63            0,                                   "typed");
64 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         min_bulk, 
65            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_min_bulk, 
66            0,                                   "min_bulk");
67 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         rx_buffer_size, 
68            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_rx_buffer_size, 
69            0,                                   "rx_buffer_size");
70 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         tx_buffer_size, 
71            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_tx_buffer_size, 
72            0,                                   "tx_buffer_size");
73 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         nagle, 
74            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_nagle, 
75            0,                                   "nagle");
76 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         keepalive_idle, 
77            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_keepalive_idle, 
78            0,                                   "keepalive_idle");
79 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         keepalive_count, 
80            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_keepalive_count, 
81            0,                                   "keepalive_count");
82 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         keepalive_intvl, 
83            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_keepalive_intvl, 
84            0,                                   "keepalive_intvl");
85
86 cfs_sysctl_table_t      ksocknal_top_ctl_table [] = {
87         &sysctl__lnet_ksocknal,
88         &sysctl__lnet_ksocknal_timeout,
89         &sysctl__lnet_ksocknal_credits,
90         &sysctl__lnet_ksocknal_peer_credits,
91         &sysctl__lnet_ksocknal_nconnds,
92         &sysctl__lnet_ksocknal_min_reconnectms,
93         &sysctl__lnet_ksocknal_max_reconnectms,
94         &sysctl__lnet_ksocknal_eager_ack,
95         &sysctl__lnet_ksocknal_typed,
96         &sysctl__lnet_ksocknal_min_bulk,
97         &sysctl__lnet_ksocknal_rx_buffer_size,
98         &sysctl__lnet_ksocknal_tx_buffer_size,
99         &sysctl__lnet_ksocknal_nagle,
100         &sysctl__lnet_ksocknal_keepalive_idle,
101         &sysctl__lnet_ksocknal_keepalive_count,
102         &sysctl__lnet_ksocknal_keepalive_intvl,
103         NULL
104 };
105
106 int
107 ksocknal_lib_tunables_init ()
108 {
109         ksocknal_tunables.ksnd_sysctl =
110                 cfs_register_sysctl_table (ksocknal_top_ctl_table, 0);
111
112         if (ksocknal_tunables.ksnd_sysctl == NULL)
113                 return -ENOMEM;
114
115         return 0;
116 }
117
118 void
119 ksocknal_lib_tunables_fini ()
120 {
121         if (ksocknal_tunables.ksnd_sysctl != NULL)
122                 cfs_unregister_sysctl_table (ksocknal_tunables.ksnd_sysctl);    
123 }
124 #else
125 int
126 ksocknal_lib_tunables_init ()
127 {
128         return 0;
129 }
130
131 void
132 ksocknal_lib_tunables_fini ()
133 {
134 }
135 #endif
136
137 /*
138  * To use bigger buffer for socket:
139  * 1. Increase nmbclusters (Cannot increased by sysctl because it's ready only, so
140  *    we must patch kernel).
141  * 2. Increase net.inet.tcp.reass.maxsegments
142  * 3. Increase net.inet.tcp.sendspace
143  * 4. Increase net.inet.tcp.recvspace
144  * 5. Increase kern.ipc.maxsockbuf
145  */
146 #define KSOCKNAL_MAX_BUFFER        (1152*1024)
147
148 void
149 ksocknal_lib_bind_irq (unsigned int irq)
150 {
151         return;
152 }
153
154 unsigned int
155 ksocknal_lib_sock_irq (cfs_socket_t *sock)
156 {
157         return 0;
158 }
159
160 int
161 ksocknal_lib_get_conn_addrs (ksock_conn_t *conn)
162
163         int rc = libcfs_sock_getaddr(conn->ksnc_sock, 1,
164                                      &conn->ksnc_ipaddr,
165                                      &conn->ksnc_port);
166
167         /* Didn't need the {get,put}connsock dance to deref ksnc_sock... */
168         LASSERT (!conn->ksnc_closing);
169
170         if (rc != 0) {
171                 CERROR ("Error %d getting sock peer IP\n", rc);
172                 return rc;
173         }
174
175         rc = libcfs_sock_getaddr(conn->ksnc_sock, 0,
176                                  &conn->ksnc_myipaddr, NULL);
177         if (rc != 0) {
178                 CERROR ("Error %d getting sock local IP\n", rc);
179                 return rc;
180         }
181
182         return 0;
183 }
184
185 #ifdef __DARWIN8__
186
187 int
188 ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
189 {
190         socket_t        sock = C2B_SOCK(conn->ksnc_sock);
191         size_t          sndlen;
192         int             nob;
193         int             rc;
194
195 #if SOCKNAL_SINGLE_FRAG_TX
196         struct iovec    scratch;
197         struct iovec   *scratchiov = &scratch;
198         unsigned int    niov = 1;
199 #else
200         struct iovec   *scratchiov = conn->ksnc_tx_scratch_iov;
201         unsigned int    niov = tx->tx_niov;
202 #endif
203         struct msghdr msg = {
204                 .msg_name       = NULL,
205                 .msg_namelen    = 0,
206                 .msg_iov        = scratchiov,
207                 .msg_iovlen     = niov,
208                 .msg_control    = NULL,
209                 .msg_controllen = 0,
210                 .msg_flags      = MSG_DONTWAIT
211         };
212         
213         int  i;
214         
215         for (nob = i = 0; i < niov; i++) {
216                 scratchiov[i] = tx->tx_iov[i];
217                 nob += scratchiov[i].iov_len;
218         } 
219         
220         /* 
221          * XXX Liang:
222          * Linux has MSG_MORE, do we have anything to
223          * reduce number of partial TCP segments sent?
224          */
225         rc = -sock_send(sock, &msg, MSG_DONTWAIT, &sndlen);
226         if (rc == 0)
227                 rc = sndlen;
228         return rc;
229 }
230
231 int
232 ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx)
233 {
234         socket_t       sock = C2B_SOCK(conn->ksnc_sock);
235         lnet_kiov_t   *kiov = tx->tx_kiov;
236         int            rc;
237         int            nob;
238         size_t         sndlen;
239
240 #if SOCKNAL_SINGLE_FRAG_TX
241         struct iovec  scratch;
242         struct iovec *scratchiov = &scratch;
243         unsigned int  niov = 1;
244 #else
245         struct iovec *scratchiov = conn->ksnc_tx_scratch_iov;
246         unsigned int  niov = tx->tx_nkiov;
247 #endif
248         struct msghdr msg = {
249                 .msg_name       = NULL,
250                 .msg_namelen    = 0,
251                 .msg_iov        = scratchiov,
252                 .msg_iovlen     = niov,
253                 .msg_control    = NULL,
254                 .msg_controllen = 0,
255                 .msg_flags      = MSG_DONTWAIT
256         };
257         
258         int           i;
259         
260         for (nob = i = 0; i < niov; i++) {
261                 scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) +
262                                          kiov[i].kiov_offset;
263                 nob += scratchiov[i].iov_len = kiov[i].kiov_len;
264         }
265
266         /* 
267          * XXX Liang:
268          * Linux has MSG_MORE, do wen have anyting to
269          * reduce number of partial TCP segments sent?
270          */
271         rc = -sock_send(sock, &msg, MSG_DONTWAIT, &sndlen);
272         for (i = 0; i < niov; i++)
273                 cfs_kunmap(kiov[i].kiov_page);
274         if (rc == 0)
275                 rc = sndlen;
276         return rc;
277 }
278
279 int
280 ksocknal_lib_recv_iov (ksock_conn_t *conn)
281 {
282 #if SOCKNAL_SINGLE_FRAG_RX
283         struct iovec  scratch;
284         struct iovec *scratchiov = &scratch;
285         unsigned int  niov = 1;
286 #else
287         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov;
288         unsigned int  niov = conn->ksnc_rx_niov;
289 #endif
290         struct iovec *iov = conn->ksnc_rx_iov;
291         struct msghdr msg = {
292                 .msg_name       = NULL,
293                 .msg_namelen    = 0,
294                 .msg_iov        = scratchiov,
295                 .msg_iovlen     = niov,
296                 .msg_control    = NULL,
297                 .msg_controllen = 0,
298                 .msg_flags      = 0
299         };
300         size_t       rcvlen;
301         int          nob;
302         int          i;
303         int          rc;
304
305         LASSERT (niov > 0);
306
307         for (nob = i = 0; i < niov; i++) {
308                 scratchiov[i] = iov[i];
309                 nob += scratchiov[i].iov_len;
310         }
311         LASSERT (nob <= conn->ksnc_rx_nob_wanted); 
312         rc = -sock_receive (C2B_SOCK(conn->ksnc_sock), &msg, MSG_DONTWAIT, &rcvlen);
313         if (rc == 0)
314                 rc = rcvlen;
315
316         return rc;
317 }
318
319 int
320 ksocknal_lib_recv_kiov (ksock_conn_t *conn)
321 {
322 #if SOCKNAL_SINGLE_FRAG_RX
323         struct iovec  scratch;
324         struct iovec *scratchiov = &scratch;
325         unsigned int  niov = 1;
326 #else
327         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov;
328         unsigned int  niov = conn->ksnc_rx_nkiov;
329 #endif
330         lnet_kiov_t   *kiov = conn->ksnc_rx_kiov;
331         struct msghdr msg = {
332                 .msg_name       = NULL,
333                 .msg_namelen    = 0,
334                 .msg_iov        = scratchiov,
335                 .msg_iovlen     = niov,
336                 .msg_control    = NULL,
337                 .msg_controllen = 0,
338                 .msg_flags      = 0
339         };
340         int          nob;
341         int          i;
342         size_t       rcvlen;
343         int          rc;
344
345         /* NB we can't trust socket ops to either consume our iovs
346          * or leave them alone. */
347         for (nob = i = 0; i < niov; i++) {
348                 scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + \
349                                          kiov[i].kiov_offset;
350                 nob += scratchiov[i].iov_len = kiov[i].kiov_len;
351         }
352         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
353         rc = -sock_receive(C2B_SOCK(conn->ksnc_sock), &msg, MSG_DONTWAIT, &rcvlen); 
354         for (i = 0; i < niov; i++)
355                 cfs_kunmap(kiov[i].kiov_page); 
356         if (rc == 0)
357                 rc = rcvlen;
358         return (rc);
359 }
360
361 void
362 ksocknal_lib_eager_ack (ksock_conn_t *conn)
363 {
364         /* XXX Liang: */
365 }
366
367 int
368 ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle)
369 {
370         socket_t       sock = C2B_SOCK(conn->ksnc_sock);
371         int            len;
372         int            rc;
373
374         rc = ksocknal_connsock_addref(conn);
375         if (rc != 0) {
376                 LASSERT (conn->ksnc_closing);
377                 *txmem = *rxmem = *nagle = 0;
378                 return (-ESHUTDOWN);
379         }
380         rc = libcfs_sock_getbuf(conn->ksnc_sock, txmem, rxmem);
381         if (rc == 0) {
382                 len = sizeof(*nagle);
383                 rc = -sock_getsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
384                                       nagle, &len);
385         }
386         ksocknal_connsock_decref(conn);
387
388         if (rc == 0)
389                 *nagle = !*nagle;
390         else
391                 *txmem = *rxmem = *nagle = 0;
392
393         return (rc);
394 }
395
396 int
397 ksocknal_lib_setup_sock (cfs_socket_t *sock)
398 {
399         int             rc; 
400         int             option; 
401         int             keep_idle; 
402         int             keep_intvl; 
403         int             keep_count; 
404         int             do_keepalive; 
405         socket_t        so = C2B_SOCK(sock);
406         struct linger   linger;
407
408         /* Ensure this socket aborts active sends immediately when we close
409          * it. */
410         linger.l_onoff = 0;
411         linger.l_linger = 0;
412         rc = -sock_setsockopt(so, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
413         if (rc != 0) {
414                 CERROR ("Can't set SO_LINGER: %d\n", rc);
415                 return (rc);
416         }
417
418         if (!*ksocknal_tunables.ksnd_nagle) { 
419                 option = 1; 
420                 rc = -sock_setsockopt(so, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option));
421                 if (rc != 0) { 
422                         CERROR ("Can't disable nagle: %d\n", rc); 
423                         return (rc);
424                 } 
425         } 
426
427         rc = libcfs_sock_setbuf(sock,
428                                 *ksocknal_tunables.ksnd_tx_buffer_size,
429                                 *ksocknal_tunables.ksnd_rx_buffer_size);
430         if (rc != 0) {
431                 CERROR ("Can't set buffer tx %d, rx %d buffers: %d\n",
432                         *ksocknal_tunables.ksnd_tx_buffer_size,
433                         *ksocknal_tunables.ksnd_rx_buffer_size, rc);
434                 return (rc);
435         }
436
437         /* snapshot tunables */ 
438         keep_idle  = *ksocknal_tunables.ksnd_keepalive_idle; 
439         keep_count = *ksocknal_tunables.ksnd_keepalive_count; 
440         keep_intvl = *ksocknal_tunables.ksnd_keepalive_intvl;
441
442         do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0); 
443         option = (do_keepalive ? 1 : 0); 
444
445         rc = -sock_setsockopt(so, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)); 
446         if (rc != 0) { 
447                 CERROR ("Can't set SO_KEEPALIVE: %d\n", rc); 
448                 return (rc);
449         }
450         
451         if (!do_keepalive)
452                 return (rc);
453         rc = -sock_setsockopt(so, IPPROTO_TCP, TCP_KEEPALIVE, 
454                               &keep_idle, sizeof(keep_idle));
455         
456         return (rc);
457 }
458
459 void
460 ksocknal_lib_push_conn(ksock_conn_t *conn)
461
462         socket_t        sock; 
463         int             val = 1; 
464         int             rc; 
465         
466         rc = ksocknal_connsock_addref(conn); 
467         if (rc != 0)            /* being shut down */ 
468                 return; 
469         sock = C2B_SOCK(conn->ksnc_sock); 
470
471         rc = -sock_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); 
472         LASSERT(rc == 0);
473
474         ksocknal_connsock_decref(conn);
475         return;
476 }
477
478 extern void ksocknal_read_callback (ksock_conn_t *conn);
479 extern void ksocknal_write_callback (ksock_conn_t *conn);
480
481 static void
482 ksocknal_upcall(socket_t so, void *arg, int waitf)
483 {
484         ksock_conn_t  *conn = (ksock_conn_t *)arg;
485         ENTRY;
486
487         read_lock (&ksocknal_data.ksnd_global_lock);
488         if (conn == NULL)
489                 goto out;
490
491         ksocknal_read_callback (conn);
492         /* XXX Liang */
493         ksocknal_write_callback (conn);
494 out:
495         read_unlock (&ksocknal_data.ksnd_global_lock);
496         EXIT;
497 }
498
499 void
500 ksocknal_lib_save_callback(cfs_socket_t *sock, ksock_conn_t *conn)
501
502         /* No callback need to save in osx */
503         return;
504 }
505
506 void
507 ksocknal_lib_set_callback(cfs_socket_t *sock, ksock_conn_t *conn)
508
509         libcfs_sock_set_cb(sock, ksocknal_upcall, (void *)conn);
510         return;
511 }
512
513 void 
514 ksocknal_lib_reset_callback(cfs_socket_t *sock, ksock_conn_t *conn)
515
516         libcfs_sock_reset_cb(sock);
517 }
518
519 #else /* !__DARWIN8__ */
520
521 int
522 ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
523
524 #if SOCKNAL_SINGLE_FRAG_TX 
525         struct iovec    scratch; 
526         struct iovec   *scratchiov = &scratch; 
527         unsigned int    niov = 1;
528 #else 
529         struct iovec   *scratchiov = conn->ksnc_tx_scratch_iov; 
530         unsigned int    niov = tx->tx_niov;
531 #endif
532         struct socket *sock = conn->ksnc_sock;
533         int            nob;
534         int            rc;
535         int            i;
536         struct uio  suio = {
537                 .uio_iov        = scratchiov,
538                 .uio_iovcnt     = niov,
539                 .uio_offset     = 0,
540                 .uio_resid      = 0,            /* This will be valued after a while */
541                 .uio_segflg     = UIO_SYSSPACE,
542                 .uio_rw         = UIO_WRITE,
543                 .uio_procp      = NULL
544         };
545         int  flags = MSG_DONTWAIT;
546         CFS_DECL_NET_DATA;
547
548         for (nob = i = 0; i < niov; i++) { 
549                 scratchiov[i] = tx->tx_iov[i]; 
550                 nob += scratchiov[i].iov_len; 
551         }
552         suio.uio_resid = nob;
553
554         CFS_NET_IN;
555         rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, flags);
556         CFS_NET_EX; 
557
558         /* NB there is no return value can indicate how many 
559          * have been sent and how many resid, we have to get 
560          * sent bytes from suio. */
561         if (rc != 0) {
562                 if (suio.uio_resid != nob &&\
563                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
564                         /* We have sent something */
565                         rc = nob - suio.uio_resid;
566                 else if ( rc == EWOULDBLOCK ) 
567                         /* Actually, EAGAIN and EWOULDBLOCK have same value in OSX */
568                         rc = -EAGAIN;   
569                 else 
570                         rc = -rc;
571         } else  /* rc == 0 */
572                 rc = nob - suio.uio_resid;
573
574         return rc;
575 }
576
577 int
578 ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx)
579 {
580 #if SOCKNAL_SINGLE_FRAG_TX || !SOCKNAL_RISK_KMAP_DEADLOCK 
581         struct iovec  scratch; 
582         struct iovec *scratchiov = &scratch; 
583         unsigned int  niov = 1;
584 #else
585         struct iovec *scratchiov = conn->ksnc_tx_scratch_iov; 
586         unsigned int  niov = tx->tx_nkiov;
587 #endif
588         struct socket *sock = conn->ksnc_sock;
589         lnet_kiov_t    *kiov = tx->tx_kiov;
590         int            nob;
591         int            rc;
592         int            i;
593         struct  uio suio = {
594                 .uio_iov        = scratchiov,
595                 .uio_iovcnt     = niov,
596                 .uio_offset     = 0, 
597                 .uio_resid      = 0,    /* It should be valued after a while */
598                 .uio_segflg     = UIO_SYSSPACE,
599                 .uio_rw         = UIO_WRITE,
600                 .uio_procp      = NULL
601         };
602         int  flags = MSG_DONTWAIT;
603         CFS_DECL_NET_DATA; 
604         
605         for (nob = i = 0; i < niov; i++) { 
606                 scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + 
607                                          kiov[i].kiov_offset; 
608                 nob += scratchiov[i].iov_len = kiov[i].kiov_len; 
609         }
610         suio.uio_resid = nob;
611
612         CFS_NET_IN;
613         rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, flags);
614         CFS_NET_EX;
615
616         for (i = 0; i < niov; i++) 
617                 cfs_kunmap(kiov[i].kiov_page);
618
619         if (rc != 0) {
620                 if (suio.uio_resid != nob &&\
621                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
622                         /* We have sent something */
623                         rc = nob - suio.uio_resid; 
624                 else if ( rc == EWOULDBLOCK ) 
625                         /* EAGAIN and EWOULD BLOCK have same value in OSX */
626                         rc = -EAGAIN;   
627                 else 
628                         rc = -rc;
629         } else  /* rc == 0 */
630                 rc = nob - suio.uio_resid;
631
632         return rc;
633 }
634
635 /*
636  * liang: Hack of inpcb and tcpcb.
637  * To get tcpcb of a socket, and call tcp_output
638  * to send quick ack.
639  */
640 struct ks_tseg_qent{
641         int foo;
642 };
643
644 struct ks_tcptemp{
645         int foo;
646 };
647
648 LIST_HEAD(ks_tsegqe_head, ks_tseg_qent);
649
650 struct ks_tcpcb {
651         struct ks_tsegqe_head t_segq;
652         int     t_dupacks;
653         struct ks_tcptemp *unused;
654         int    t_timer[4];
655         struct inpcb *t_inpcb;
656         int    t_state;
657         u_int  t_flags;
658         /*
659          * There are more fields but we dont need
660          * ......
661          */
662 };
663
664 #define TF_ACKNOW       0x00001
665 #define TF_DELACK       0x00002
666
667 struct ks_inpcb {
668         LIST_ENTRY(ks_inpcb) inp_hash;
669         struct  in_addr reserved1;
670         struct  in_addr reserved2;
671         u_short inp_fport;
672         u_short inp_lport;
673         LIST_ENTRY(inpcb) inp_list;
674         caddr_t inp_ppcb;
675         /*
676          * There are more fields but we dont need
677          * ......
678          */
679 };
680
681 #define ks_sotoinpcb(so)   ((struct ks_inpcb *)(so)->so_pcb)
682 #define ks_intotcpcb(ip)   ((struct ks_tcpcb *)(ip)->inp_ppcb)
683 #define ks_sototcpcb(so)   (intotcpcb(sotoinpcb(so)))
684
685 void
686 ksocknal_lib_eager_ack (ksock_conn_t *conn)
687 {
688         struct socket *sock = conn->ksnc_sock;
689         struct ks_inpcb  *inp = ks_sotoinpcb(sock);
690         struct ks_tcpcb  *tp = ks_intotcpcb(inp);
691         int s;
692         CFS_DECL_NET_DATA;
693
694         extern int tcp_output(register struct ks_tcpcb *tp);
695
696         CFS_NET_IN;
697         s = splnet();
698
699         /*
700          * No TCP_QUICKACK supported in BSD, so I have to call tcp_fasttimo
701          * to send immediate ACK. 
702          */
703         if (tp && tp->t_flags & TF_DELACK){
704                 tp->t_flags &= ~TF_DELACK;
705                 tp->t_flags |= TF_ACKNOW;
706                 (void) tcp_output(tp);
707         }
708         splx(s);
709
710         CFS_NET_EX;
711
712         return;
713 }
714
715 int
716 ksocknal_lib_recv_iov (ksock_conn_t *conn)
717 {
718 #if SOCKNAL_SINGLE_FRAG_RX 
719         struct iovec  scratch; 
720         struct iovec *scratchiov = &scratch; 
721         unsigned int  niov = 1;
722 #else 
723         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov; 
724         unsigned int  niov = conn->ksnc_rx_niov;
725 #endif
726         struct iovec *iov = conn->ksnc_rx_iov;
727         int          nob;
728         int          rc;
729         int          i;
730         struct uio  ruio = {
731                 .uio_iov        = scratchiov,
732                 .uio_iovcnt     = niov,
733                 .uio_offset     = 0,
734                 .uio_resid      = 0,    /* It should be valued after a while */
735                 .uio_segflg     = UIO_SYSSPACE,
736                 .uio_rw         = UIO_READ,
737                 .uio_procp      = NULL
738         };
739         int         flags = MSG_DONTWAIT;
740         CFS_DECL_NET_DATA;
741
742         for (nob = i = 0; i < niov; i++) { 
743                 scratchiov[i] = iov[i]; 
744                 nob += scratchiov[i].iov_len; 
745         } 
746         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
747
748         ruio.uio_resid = nob;
749
750         CFS_NET_IN;
751         rc = soreceive(conn->ksnc_sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, (struct mbuf **)0, &flags);
752         CFS_NET_EX;
753         if (rc){
754                 if (ruio.uio_resid != nob && \
755                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK || rc == EAGAIN))
756                         /* data particially received */
757                         rc = nob - ruio.uio_resid; 
758                 else if (rc == EWOULDBLOCK) 
759                         /* EAGAIN and EWOULD BLOCK have same value in OSX */
760                         rc = -EAGAIN; 
761                 else
762                         rc = -rc;
763         } else 
764                 rc = nob - ruio.uio_resid;
765
766         return (rc);
767 }
768
769 int
770 ksocknal_lib_recv_kiov (ksock_conn_t *conn)
771 {
772 #if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK 
773         struct iovec  scratch; 
774         struct iovec *scratchiov = &scratch; 
775         unsigned int  niov = 1;
776 #else 
777         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov; 
778         unsigned int  niov = conn->ksnc_rx_nkiov;
779 #endif
780         lnet_kiov_t    *kiov = conn->ksnc_rx_kiov;
781         int           nob;
782         int           rc;
783         int           i;
784         struct uio  ruio = {
785                 .uio_iov        = scratchiov,
786                 .uio_iovcnt     = niov,
787                 .uio_offset     = 0,
788                 .uio_resid      = 0,
789                 .uio_segflg     = UIO_SYSSPACE,
790                 .uio_rw         = UIO_READ,
791                 .uio_procp      = NULL
792         };
793         int         flags = MSG_DONTWAIT;
794         CFS_DECL_NET_DATA;
795
796         for (nob = i = 0; i < niov; i++) { 
797                 scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + kiov[i].kiov_offset; 
798                 nob += scratchiov[i].iov_len = kiov[i].kiov_len; 
799         } 
800         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
801
802         ruio.uio_resid = nob;
803
804         CFS_NET_IN;
805         rc = soreceive(conn->ksnc_sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, NULL, &flags);
806         CFS_NET_EX;
807
808         for (i = 0; i < niov; i++) 
809                 cfs_kunmap(kiov[i].kiov_page);
810
811         if (rc){
812                 if (ruio.uio_resid != nob && \
813                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
814                         /* data particially received */
815                         rc = nob - ruio.uio_resid; 
816                 else if (rc == EWOULDBLOCK)
817                         /* receive blocked, EWOULDBLOCK == EAGAIN */ 
818                         rc = -EAGAIN; 
819                 else
820                         rc = -rc;
821         } else
822                 rc = nob - ruio.uio_resid;
823
824         return (rc);
825 }
826
827 int
828 ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle)
829 {
830         struct socket *sock = conn->ksnc_sock;
831         int            rc;
832
833         rc = ksocknal_connsock_addref(conn);
834         if (rc != 0) {
835                 LASSERT (conn->ksnc_closing);
836                 *txmem = *rxmem = *nagle = 0;
837                 return -ESHUTDOWN;
838         }
839         rc = libcfs_sock_getbuf(sock, txmem, rxmem);
840         if (rc == 0) {
841                 struct sockopt  sopt;
842                 int            len;
843                 CFS_DECL_NET_DATA;
844
845                 len = sizeof(*nagle);
846                 bzero(&sopt, sizeof sopt);
847                 sopt.sopt_dir = SOPT_GET; 
848                 sopt.sopt_level = IPPROTO_TCP;
849                 sopt.sopt_name = TCP_NODELAY;
850                 sopt.sopt_val = nagle;
851                 sopt.sopt_valsize = len;
852
853                 CFS_NET_IN;
854                 rc = -sogetopt(sock, &sopt);
855                 CFS_NET_EX;
856         }
857
858         ksocknal_connsock_decref(conn);
859
860         if (rc == 0)
861                 *nagle = !*nagle;
862         else
863                 *txmem = *rxmem = *nagle = 0;
864         return (rc);
865 }
866
867 int
868 ksocknal_lib_setup_sock (struct socket *so)
869 {
870         struct sockopt  sopt;
871         int             rc; 
872         int             option; 
873         int             keep_idle; 
874         int             keep_intvl; 
875         int             keep_count; 
876         int             do_keepalive; 
877         struct linger   linger;
878         CFS_DECL_NET_DATA;
879
880         rc = libcfs_sock_setbuf(so,
881                                 *ksocknal_tunables.ksnd_tx_buffer_size,
882                                 *ksocknal_tunables.ksnd_rx_buffer_size);
883         if (rc != 0) {
884                 CERROR ("Can't set buffer tx %d, rx %d buffers: %d\n",
885                         *ksocknal_tunables.ksnd_tx_buffer_size,
886                         *ksocknal_tunables.ksnd_rx_buffer_size, rc);
887                 return (rc);
888         }
889
890         /* Ensure this socket aborts active sends immediately when we close
891          * it. */
892         bzero(&sopt, sizeof sopt);
893
894         linger.l_onoff = 0;
895         linger.l_linger = 0;
896         sopt.sopt_dir = SOPT_SET;
897         sopt.sopt_level = SOL_SOCKET;
898         sopt.sopt_name = SO_LINGER;
899         sopt.sopt_val = &linger;
900         sopt.sopt_valsize = sizeof(linger);
901
902         CFS_NET_IN;
903         rc = -sosetopt(so, &sopt);
904         if (rc != 0) {
905                 CERROR ("Can't set SO_LINGER: %d\n", rc);
906                 goto out;
907         }
908
909         if (!*ksocknal_tunables.ksnd_nagle) { 
910                 option = 1; 
911                 bzero(&sopt, sizeof sopt);
912                 sopt.sopt_dir = SOPT_SET; 
913                 sopt.sopt_level = IPPROTO_TCP;
914                 sopt.sopt_name = TCP_NODELAY; 
915                 sopt.sopt_val = &option; 
916                 sopt.sopt_valsize = sizeof(option);
917                 rc = -sosetopt(so, &sopt);
918                 if (rc != 0) { 
919                         CERROR ("Can't disable nagle: %d\n", rc); 
920                         goto out;
921                 } 
922         } 
923
924         /* snapshot tunables */ 
925         keep_idle  = *ksocknal_tunables.ksnd_keepalive_idle; 
926         keep_count = *ksocknal_tunables.ksnd_keepalive_count; 
927         keep_intvl = *ksocknal_tunables.ksnd_keepalive_intvl;
928
929         do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0); 
930         option = (do_keepalive ? 1 : 0); 
931         bzero(&sopt, sizeof sopt); 
932         sopt.sopt_dir = SOPT_SET; 
933         sopt.sopt_level = SOL_SOCKET; 
934         sopt.sopt_name = SO_KEEPALIVE; 
935         sopt.sopt_val = &option; 
936         sopt.sopt_valsize = sizeof(option); 
937         rc = -sosetopt(so, &sopt); 
938         if (rc != 0) { 
939                 CERROR ("Can't set SO_KEEPALIVE: %d\n", rc); 
940                 goto out; 
941         }
942         
943         if (!do_keepalive) { 
944                 /* no more setting, just return */
945                 rc = 0;
946                 goto out;
947         } 
948         
949         bzero(&sopt, sizeof sopt); 
950         sopt.sopt_dir = SOPT_SET; 
951         sopt.sopt_level = IPPROTO_TCP; 
952         sopt.sopt_name = TCP_KEEPALIVE; 
953         sopt.sopt_val = &keep_idle; 
954         sopt.sopt_valsize = sizeof(keep_idle); 
955         rc = -sosetopt(so, &sopt); 
956         if (rc != 0) { 
957                 CERROR ("Can't set TCP_KEEPALIVE : %d\n", rc); 
958                 goto out; 
959         }
960 out:
961         CFS_NET_EX;
962         return (rc);
963 }
964
965 void
966 ksocknal_lib_push_conn(ksock_conn_t *conn)
967
968         struct socket   *sock; 
969         struct sockopt  sopt; 
970         int             val = 1; 
971         int             rc; 
972         CFS_DECL_NET_DATA; 
973         
974         rc = ksocknal_connsock_addref(conn); 
975         if (rc != 0)            /* being shut down */ 
976                 return; 
977         sock = conn->ksnc_sock; 
978         bzero(&sopt, sizeof sopt); 
979         sopt.sopt_dir = SOPT_SET; 
980         sopt.sopt_level = IPPROTO_TCP; 
981         sopt.sopt_name = TCP_NODELAY; 
982         sopt.sopt_val = &val; 
983         sopt.sopt_valsize = sizeof val; 
984
985         CFS_NET_IN; 
986         sosetopt(sock, &sopt); 
987         CFS_NET_EX; 
988
989         ksocknal_connsock_decref(conn);
990         return;
991 }
992
993
994 extern void ksocknal_read_callback (ksock_conn_t *conn);
995 extern void ksocknal_write_callback (ksock_conn_t *conn);
996
997 static void
998 ksocknal_upcall(struct socket *so, caddr_t arg, int waitf)
999 {
1000         ksock_conn_t  *conn = (ksock_conn_t *)arg;
1001         ENTRY;
1002
1003         read_lock (&ksocknal_data.ksnd_global_lock);
1004         if (conn == NULL)
1005                 goto out;
1006
1007         if (so->so_rcv.sb_flags & SB_UPCALL) {
1008                 extern int soreadable(struct socket *so);
1009                 if (conn->ksnc_rx_nob_wanted && soreadable(so))
1010                         /* To verify whether the upcall is for receive */
1011                         ksocknal_read_callback (conn);
1012         }
1013         /* go foward? */
1014         if (so->so_snd.sb_flags & SB_UPCALL){
1015                 extern int sowriteable(struct socket *so);
1016                 if (sowriteable(so))
1017                         /* socket is writable */
1018                         ksocknal_write_callback(conn);
1019         }
1020 out:
1021         read_unlock (&ksocknal_data.ksnd_global_lock);
1022
1023         EXIT;
1024 }
1025
1026 void
1027 ksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn)
1028
1029         /* No callback need to save in osx */
1030         return;
1031 }
1032
1033 void
1034 ksocknal_lib_set_callback(struct socket *sock, ksock_conn_t *conn)
1035
1036         CFS_DECL_NET_DATA;
1037
1038         CFS_NET_IN;
1039         sock->so_upcallarg = (void *)conn;
1040         sock->so_upcall = ksocknal_upcall; 
1041         sock->so_snd.sb_timeo = 0; 
1042         sock->so_rcv.sb_timeo = cfs_time_seconds(2);
1043         sock->so_rcv.sb_flags |= SB_UPCALL; 
1044         sock->so_snd.sb_flags |= SB_UPCALL; 
1045         CFS_NET_EX;
1046         return;
1047 }
1048
1049 void
1050 ksocknal_lib_act_callback(struct socket *sock, ksock_conn_t *conn)
1051 {
1052         CFS_DECL_NET_DATA;
1053
1054         CFS_NET_IN;
1055         ksocknal_upcall (sock, (void *)conn, 0);
1056         CFS_NET_EX;
1057 }
1058
1059 void 
1060 ksocknal_lib_reset_callback(struct socket *sock, ksock_conn_t *conn)
1061
1062         CFS_DECL_NET_DATA;
1063
1064         CFS_NET_IN;
1065         sock->so_rcv.sb_flags &= ~SB_UPCALL; 
1066         sock->so_snd.sb_flags &= ~SB_UPCALL;
1067         sock->so_upcall = NULL; 
1068         sock->so_upcallarg = NULL; 
1069         CFS_NET_EX;
1070 }
1071
1072 #endif  /* !__DARWIN8__ */