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