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