Whamcloud - gitweb
821522d139bf7d0dd9ac17b78b9ed18be6fa11ff
[fs/lustre-release.git] / lnet / klnds / socklnd / socklnd_lib-linux.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see [sun.com URL with a
20  * copy of GPLv2].
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #include "socklnd.h"
38
39 # if defined(CONFIG_SYSCTL) && !CFS_SYSFS_MODULE_PARM
40 static cfs_sysctl_table_t ksocknal_ctl_table[21];
41
42 cfs_sysctl_table_t ksocknal_top_ctl_table[] = {
43         {
44                 .ctl_name = 200,
45                 .procname = "socknal",
46                 .data     = NULL,
47                 .maxlen   = 0,
48                 .mode     = 0555,
49                 .child    = ksocknal_ctl_table
50         },
51         { 0 }
52 };
53
54 int
55 ksocknal_lib_tunables_init ()
56 {
57         int    i = 0;
58         int    j = 1;
59
60         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
61                 .ctl_name = j++,
62                 .procname = "timeout",
63                 .data     = ksocknal_tunables.ksnd_timeout,
64                 .maxlen   = sizeof (int),
65                 .mode     = 0644,
66                 .proc_handler = &proc_dointvec
67         };
68         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
69                 .ctl_name = j++,
70                 .procname = "credits",
71                 .data     = ksocknal_tunables.ksnd_credits,
72                 .maxlen   = sizeof (int),
73                 .mode     = 0444,
74                 .proc_handler = &proc_dointvec
75         };
76         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
77                 .ctl_name = j++,
78                 .procname = "peer_credits",
79                 .data     = ksocknal_tunables.ksnd_peercredits,
80                 .maxlen   = sizeof (int),
81                 .mode     = 0444,
82                 .proc_handler = &proc_dointvec
83         };
84         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
85                 .ctl_name = j++,
86                 .procname = "nconnds",
87                 .data     = ksocknal_tunables.ksnd_nconnds,
88                 .maxlen   = sizeof (int),
89                 .mode     = 0444,
90                 .proc_handler = &proc_dointvec
91         };
92         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
93                 .ctl_name = j++,
94                 .procname = "min_reconnectms",
95                 .data     = ksocknal_tunables.ksnd_min_reconnectms,
96                 .maxlen   = sizeof (int),
97                 .mode     = 0444,
98                 .proc_handler = &proc_dointvec
99         };
100         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
101                 .ctl_name = j++,
102                 .procname = "max_reconnectms",
103                 .data     = ksocknal_tunables.ksnd_max_reconnectms,
104                 .maxlen   = sizeof (int),
105                 .mode     = 0444,
106                 .proc_handler = &proc_dointvec
107         };
108         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
109                 .ctl_name = j++,
110                 .procname = "eager_ack",
111                 .data     = ksocknal_tunables.ksnd_eager_ack,
112                 .maxlen   = sizeof (int),
113                 .mode     = 0644,
114                 .proc_handler = &proc_dointvec
115         };
116         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
117                 .ctl_name = j++,
118                 .procname = "zero_copy",
119                 .data     = ksocknal_tunables.ksnd_zc_min_frag,
120                 .maxlen   = sizeof (int),
121                 .mode     = 0644,
122                 .proc_handler = &proc_dointvec
123         };
124         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
125                 .ctl_name = j++,
126                 .procname = "typed",
127                 .data     = ksocknal_tunables.ksnd_typed_conns,
128                 .maxlen   = sizeof (int),
129                 .mode     = 0444,
130                 .proc_handler = &proc_dointvec
131         };
132         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
133                 .ctl_name = j++,
134                 .procname = "min_bulk",
135                 .data     = ksocknal_tunables.ksnd_min_bulk,
136                 .maxlen   = sizeof (int),
137                 .mode     = 0644,
138                 .proc_handler = &proc_dointvec
139         };
140         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
141                 .ctl_name = j++,
142                 .procname = "rx_buffer_size",
143                 .data     = ksocknal_tunables.ksnd_rx_buffer_size,
144                 .maxlen   = sizeof(int),
145                 .mode     = 0644,
146                 .proc_handler = &proc_dointvec
147         };
148         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
149                 .ctl_name = j++,
150                 .procname = "tx_buffer_size",
151                 .data     = ksocknal_tunables.ksnd_tx_buffer_size,
152                 .maxlen   = sizeof(int),
153                 .mode     = 0644,
154                 .proc_handler = &proc_dointvec
155         };
156         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
157                 .ctl_name = j++,
158                 .procname = "nagle",
159                 .data     = ksocknal_tunables.ksnd_nagle,
160                 .maxlen   = sizeof(int),
161                 .mode     = 0644,
162                 .proc_handler = &proc_dointvec
163         };
164 #ifdef CPU_AFFINITY
165         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
166                 .ctl_name = j++,
167                 .procname = "irq_affinity",
168                 .data     = ksocknal_tunables.ksnd_irq_affinity,
169                 .maxlen   = sizeof(int),
170                 .mode     = 0644,
171                 .proc_handler = &proc_dointvec
172         };
173 #endif
174         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
175                 .ctl_name = j++,
176                 .procname = "keepalive_idle",
177                 .data     = ksocknal_tunables.ksnd_keepalive_idle,
178                 .maxlen   = sizeof(int),
179                 .mode     = 0644,
180                 .proc_handler = &proc_dointvec
181         };
182         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
183                 .ctl_name = j++,
184                 .procname = "keepalive_count",
185                 .data     = ksocknal_tunables.ksnd_keepalive_count,
186                 .maxlen   = sizeof(int),
187                 .mode     = 0644,
188                 .proc_handler = &proc_dointvec
189         };
190         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
191                 .ctl_name = j++,
192                 .procname = "keepalive_intvl",
193                 .data     = ksocknal_tunables.ksnd_keepalive_intvl,
194                 .maxlen   = sizeof(int),
195                 .mode     = 0644,
196                 .proc_handler = &proc_dointvec
197         };
198 #ifdef SOCKNAL_BACKOFF
199         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
200                 .ctl_name = j++,
201                 .procname = "backoff_init",
202                 .data     = ksocknal_tunables.ksnd_backoff_init,
203                 .maxlen   = sizeof(int),
204                 .mode     = 0644,
205                 .proc_handler = &proc_dointvec
206         };
207         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
208                 .ctl_name = j++,
209                 .procname = "backoff_max",
210                 .data     = ksocknal_tunables.ksnd_backoff_max,
211                 .maxlen   = sizeof(int),
212                 .mode     = 0644,
213                 .proc_handler = &proc_dointvec
214         };
215 #endif
216 #if SOCKNAL_VERSION_DEBUG
217         ksocknal_ctl_table[i++] = (cfs_sysctl_table_t) {
218                 .ctl_name = j++,
219                 .procname = "protocol",
220                 .data     = ksocknal_tunables.ksnd_protocol,
221                 .maxlen   = sizeof(int),
222                 .mode     = 0644,
223                 .proc_handler = &proc_dointvec
224         };
225 #endif
226         ksocknal_ctl_table[i++] =  (cfs_sysctl_table_t) { 0 };
227
228         LASSERT (j == i);
229         LASSERT (i <= sizeof(ksocknal_ctl_table)/sizeof(ksocknal_ctl_table[0]));
230
231         ksocknal_tunables.ksnd_sysctl =
232                 cfs_register_sysctl_table(ksocknal_top_ctl_table, 0);
233
234         if (ksocknal_tunables.ksnd_sysctl == NULL)
235                 CWARN("Can't setup /proc tunables\n");
236
237         return 0;
238 }
239
240 void
241 ksocknal_lib_tunables_fini ()
242 {
243         if (ksocknal_tunables.ksnd_sysctl != NULL)
244                 cfs_unregister_sysctl_table(ksocknal_tunables.ksnd_sysctl);
245 }
246 #else
247 int
248 ksocknal_lib_tunables_init ()
249 {
250         return 0;
251 }
252
253 void
254 ksocknal_lib_tunables_fini ()
255 {
256 }
257 #endif /* # if CONFIG_SYSCTL && !CFS_SYSFS_MODULE_PARM */
258
259 void
260 ksocknal_lib_bind_irq (unsigned int irq)
261 {
262 #if (defined(CONFIG_SMP) && defined(CPU_AFFINITY))
263         int              bind;
264         int              cpu;
265         char             cmdline[64];
266         ksock_irqinfo_t *info;
267         char            *argv[] = {"/bin/sh",
268                                    "-c",
269                                    cmdline,
270                                    NULL};
271         char            *envp[] = {"HOME=/",
272                                    "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
273                                    NULL};
274
275         LASSERT (irq < NR_IRQS);
276         if (irq == 0)              /* software NIC or affinity disabled */
277                 return;
278
279         info = &ksocknal_data.ksnd_irqinfo[irq];
280
281         write_lock_bh (&ksocknal_data.ksnd_global_lock);
282
283         LASSERT (info->ksni_valid);
284         bind = !info->ksni_bound;
285         info->ksni_bound = 1;
286
287         write_unlock_bh (&ksocknal_data.ksnd_global_lock);
288
289         if (!bind)                              /* bound already */
290                 return;
291
292         cpu = ksocknal_irqsched2cpu(info->ksni_sched);
293         snprintf (cmdline, sizeof (cmdline),
294                   "echo %d > /proc/irq/%u/smp_affinity", 1 << cpu, irq);
295
296         LCONSOLE_INFO("Binding irq %u to CPU %d with cmd: %s\n",
297                       irq, cpu, cmdline);
298
299         /* FIXME: Find a better method of setting IRQ affinity...
300          */
301
302         USERMODEHELPER(argv[0], argv, envp);
303 #endif
304 }
305
306 int
307 ksocknal_lib_get_conn_addrs (ksock_conn_t *conn)
308 {
309         int rc = libcfs_sock_getaddr(conn->ksnc_sock, 1,
310                                      &conn->ksnc_ipaddr,
311                                      &conn->ksnc_port);
312
313         /* Didn't need the {get,put}connsock dance to deref ksnc_sock... */
314         LASSERT (!conn->ksnc_closing);
315
316         if (rc != 0) {
317                 CERROR ("Error %d getting sock peer IP\n", rc);
318                 return rc;
319         }
320
321         rc = libcfs_sock_getaddr(conn->ksnc_sock, 0,
322                                  &conn->ksnc_myipaddr, NULL);
323         if (rc != 0) {
324                 CERROR ("Error %d getting sock local IP\n", rc);
325                 return rc;
326         }
327
328         return 0;
329 }
330
331 unsigned int
332 ksocknal_lib_sock_irq (struct socket *sock)
333 {
334         int                irq = 0;
335 #ifdef CPU_AFFINITY
336         struct dst_entry  *dst;
337
338         if (!*ksocknal_tunables.ksnd_irq_affinity)
339                 return 0;
340
341         dst = sk_dst_get (sock->sk);
342         if (dst != NULL) {
343                 if (dst->dev != NULL) {
344                         irq = dst->dev->irq;
345                         if (irq >= NR_IRQS) {
346                                 CERROR ("Unexpected IRQ %x\n", irq);
347                                 irq = 0;
348                         }
349                 }
350                 dst_release (dst);
351         }
352
353 #endif
354         return irq;
355 }
356
357 int
358 ksocknal_lib_zc_capable(struct socket *sock)
359 {
360         int  caps = sock->sk->sk_route_caps;
361
362         /* ZC if the socket supports scatter/gather and doesn't need software
363          * checksums */
364         return ((caps & NETIF_F_SG) != 0 &&
365                 (caps & (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)) != 0);
366 }
367
368 int
369 ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
370 {
371         struct socket *sock = conn->ksnc_sock;
372         int            nob;
373         int            rc;
374
375         if (*ksocknal_tunables.ksnd_enable_csum        && /* checksum enabled */
376             conn->ksnc_proto == &ksocknal_protocol_v2x && /* V2.x connection  */
377             tx->tx_nob == tx->tx_resid                 && /* frist sending    */
378             tx->tx_msg.ksm_csum == 0)                     /* not checksummed  */
379                 ksocknal_lib_csum_tx(tx);
380
381         /* NB we can't trust socket ops to either consume our iovs
382          * or leave them alone. */
383
384         {
385 #if SOCKNAL_SINGLE_FRAG_TX
386                 struct iovec    scratch;
387                 struct iovec   *scratchiov = &scratch;
388                 unsigned int    niov = 1;
389 #else
390                 struct iovec   *scratchiov = conn->ksnc_tx_scratch_iov;
391                 unsigned int    niov = tx->tx_niov;
392 #endif
393                 struct msghdr msg = {
394                         .msg_name       = NULL,
395                         .msg_namelen    = 0,
396                         .msg_iov        = scratchiov,
397                         .msg_iovlen     = niov,
398                         .msg_control    = NULL,
399                         .msg_controllen = 0,
400                         .msg_flags      = MSG_DONTWAIT
401                 };
402                 mm_segment_t oldmm = get_fs();
403                 int  i;
404
405                 for (nob = i = 0; i < niov; i++) {
406                         scratchiov[i] = tx->tx_iov[i];
407                         nob += scratchiov[i].iov_len;
408                 }
409
410                 if (!list_empty(&conn->ksnc_tx_queue) ||
411                     nob < tx->tx_resid)
412                         msg.msg_flags |= MSG_MORE;
413
414                 set_fs (KERNEL_DS);
415                 rc = sock_sendmsg(sock, &msg, nob);
416                 set_fs (oldmm);
417         }
418         return rc;
419 }
420
421 int
422 ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx)
423 {
424         struct socket *sock = conn->ksnc_sock;
425         lnet_kiov_t    *kiov = tx->tx_kiov;
426         int            rc;
427         int            nob;
428
429         /* NB we can't trust socket ops to either consume our iovs
430          * or leave them alone. */
431
432         if (kiov->kiov_len >= *ksocknal_tunables.ksnd_zc_min_frag &&
433             tx->tx_msg.ksm_zc_req_cookie != 0) {
434                 /* Zero copy is enabled */
435                 struct sock   *sk = sock->sk;
436                 struct page   *page = kiov->kiov_page;
437                 int            offset = kiov->kiov_offset;
438                 int            fragsize = kiov->kiov_len;
439                 int            msgflg = MSG_DONTWAIT;
440
441                 CDEBUG(D_NET, "page %p + offset %x for %d\n",
442                                page, offset, kiov->kiov_len);
443
444                 if (!list_empty(&conn->ksnc_tx_queue) ||
445                     fragsize < tx->tx_resid)
446                         msgflg |= MSG_MORE;
447
448                 if (sk->sk_prot->sendpage != NULL) {
449                         rc = sk->sk_prot->sendpage(sk, page,
450                                                    offset, fragsize, msgflg);
451                 } else {
452                         rc = tcp_sendpage(sock, page, offset, fragsize, msgflg);
453                 }
454         } else {
455 #if SOCKNAL_SINGLE_FRAG_TX || !SOCKNAL_RISK_KMAP_DEADLOCK
456                 struct iovec  scratch;
457                 struct iovec *scratchiov = &scratch;
458                 unsigned int  niov = 1;
459 #else
460 #ifdef CONFIG_HIGHMEM
461 #warning "XXX risk of kmap deadlock on multiple frags..."
462 #endif
463                 struct iovec *scratchiov = conn->ksnc_tx_scratch_iov;
464                 unsigned int  niov = tx->tx_nkiov;
465 #endif
466                 struct msghdr msg = {
467                         .msg_name       = NULL,
468                         .msg_namelen    = 0,
469                         .msg_iov        = scratchiov,
470                         .msg_iovlen     = niov,
471                         .msg_control    = NULL,
472                         .msg_controllen = 0,
473                         .msg_flags      = MSG_DONTWAIT
474                 };
475                 mm_segment_t  oldmm = get_fs();
476                 int           i;
477
478                 for (nob = i = 0; i < niov; i++) {
479                         scratchiov[i].iov_base = kmap(kiov[i].kiov_page) +
480                                                  kiov[i].kiov_offset;
481                         nob += scratchiov[i].iov_len = kiov[i].kiov_len;
482                 }
483
484                 if (!list_empty(&conn->ksnc_tx_queue) ||
485                     nob < tx->tx_resid)
486                         msg.msg_flags |= MSG_MORE;
487
488                 set_fs (KERNEL_DS);
489                 rc = sock_sendmsg(sock, &msg, nob);
490                 set_fs (oldmm);
491
492                 for (i = 0; i < niov; i++)
493                         kunmap(kiov[i].kiov_page);
494         }
495         return rc;
496 }
497
498 void
499 ksocknal_lib_eager_ack (ksock_conn_t *conn)
500 {
501         int            opt = 1;
502         mm_segment_t   oldmm = get_fs();
503         struct socket *sock = conn->ksnc_sock;
504
505         /* Remind the socket to ACK eagerly.  If I don't, the socket might
506          * think I'm about to send something it could piggy-back the ACK
507          * on, introducing delay in completing zero-copy sends in my
508          * peer. */
509
510         set_fs(KERNEL_DS);
511         sock->ops->setsockopt (sock, SOL_TCP, TCP_QUICKACK,
512                                (char *)&opt, sizeof (opt));
513         set_fs(oldmm);
514 }
515
516 int
517 ksocknal_lib_recv_iov (ksock_conn_t *conn)
518 {
519 #if SOCKNAL_SINGLE_FRAG_RX
520         struct iovec  scratch;
521         struct iovec *scratchiov = &scratch;
522         unsigned int  niov = 1;
523 #else
524         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov;
525         unsigned int  niov = conn->ksnc_rx_niov;
526 #endif
527         struct iovec *iov = conn->ksnc_rx_iov;
528         struct msghdr msg = {
529                 .msg_name       = NULL,
530                 .msg_namelen    = 0,
531                 .msg_iov        = scratchiov,
532                 .msg_iovlen     = niov,
533                 .msg_control    = NULL,
534                 .msg_controllen = 0,
535                 .msg_flags      = 0
536         };
537         mm_segment_t oldmm = get_fs();
538         int          nob;
539         int          i;
540         int          rc;
541         int          fragnob;
542         int          sum;
543         __u32        saved_csum;
544
545         /* NB we can't trust socket ops to either consume our iovs
546          * or leave them alone. */
547         LASSERT (niov > 0);
548
549         for (nob = i = 0; i < niov; i++) {
550                 scratchiov[i] = iov[i];
551                 nob += scratchiov[i].iov_len;
552         }
553         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
554
555         set_fs (KERNEL_DS);
556         rc = sock_recvmsg (conn->ksnc_sock, &msg, nob, MSG_DONTWAIT);
557         /* NB this is just a boolean..........................^ */
558         set_fs (oldmm);
559
560         saved_csum = 0;
561         if (conn->ksnc_proto == &ksocknal_protocol_v2x) {
562                 saved_csum = conn->ksnc_msg.ksm_csum;
563                 conn->ksnc_msg.ksm_csum = 0;
564         }
565
566         if (saved_csum != 0) {
567                 /* accumulate checksum */
568                 for (i = 0, sum = rc; sum > 0; i++, sum -= fragnob) {
569                         LASSERT (i < niov);
570
571                         fragnob = iov[i].iov_len;
572                         if (fragnob > sum)
573                                 fragnob = sum;
574
575                         conn->ksnc_rx_csum = ksocknal_csum(conn->ksnc_rx_csum,
576                                                            iov[i].iov_base, fragnob);
577                 }
578                 conn->ksnc_msg.ksm_csum = saved_csum;
579         }
580
581         return rc;
582 }
583
584 int
585 ksocknal_lib_recv_kiov (ksock_conn_t *conn)
586 {
587 #if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK
588         struct iovec  scratch;
589         struct iovec *scratchiov = &scratch;
590         unsigned int  niov = 1;
591 #else
592 #ifdef CONFIG_HIGHMEM
593 #warning "XXX risk of kmap deadlock on multiple frags..."
594 #endif
595         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov;
596         unsigned int  niov = conn->ksnc_rx_nkiov;
597 #endif
598         lnet_kiov_t   *kiov = conn->ksnc_rx_kiov;
599         struct msghdr msg = {
600                 .msg_name       = NULL,
601                 .msg_namelen    = 0,
602                 .msg_iov        = scratchiov,
603                 .msg_iovlen     = niov,
604                 .msg_control    = NULL,
605                 .msg_controllen = 0,
606                 .msg_flags      = 0
607         };
608         mm_segment_t oldmm = get_fs();
609         int          nob;
610         int          i;
611         int          rc;
612         void        *base;
613         int          sum;
614         int          fragnob;
615
616         /* NB we can't trust socket ops to either consume our iovs
617          * or leave them alone. */
618         for (nob = i = 0; i < niov; i++) {
619                 scratchiov[i].iov_base = kmap(kiov[i].kiov_page) + kiov[i].kiov_offset;
620                 nob += scratchiov[i].iov_len = kiov[i].kiov_len;
621         }
622         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
623
624         set_fs (KERNEL_DS);
625         rc = sock_recvmsg (conn->ksnc_sock, &msg, nob, MSG_DONTWAIT);
626         /* NB this is just a boolean.......................^ */
627         set_fs (oldmm);
628
629         if (conn->ksnc_msg.ksm_csum != 0) {
630                 for (i = 0, sum = rc; sum > 0; i++, sum -= fragnob) {
631                         LASSERT (i < niov);
632
633                         /* Dang! have to kmap again because I have nowhere to stash the
634                          * mapped address.  But by doing it while the page is still
635                          * mapped, the kernel just bumps the map count and returns me
636                          * the address it stashed. */
637                         base = kmap(kiov[i].kiov_page) + kiov[i].kiov_offset;
638                         fragnob = kiov[i].kiov_len;
639                         if (fragnob > sum)
640                                 fragnob = sum;
641
642                         conn->ksnc_rx_csum = ksocknal_csum(conn->ksnc_rx_csum,
643                                                            base, fragnob);
644
645                         kunmap(kiov[i].kiov_page);
646                 }
647         }
648         for (i = 0; i < niov; i++)
649                 kunmap(kiov[i].kiov_page);
650
651         return (rc);
652 }
653
654 void
655 ksocknal_lib_csum_tx(ksock_tx_t *tx)
656 {
657         int          i;
658         __u32        csum;
659         void        *base;
660
661         LASSERT(tx->tx_iov[0].iov_base == (void *)&tx->tx_msg);
662         LASSERT(tx->tx_conn != NULL);
663         LASSERT(tx->tx_conn->ksnc_proto == &ksocknal_protocol_v2x);
664
665         tx->tx_msg.ksm_csum = 0;
666
667         csum = ksocknal_csum(~0, (void *)tx->tx_iov[0].iov_base,
668                              tx->tx_iov[0].iov_len);
669
670         if (tx->tx_kiov != NULL) {
671                 for (i = 0; i < tx->tx_nkiov; i++) {
672                         base = kmap(tx->tx_kiov[i].kiov_page) +
673                                tx->tx_kiov[i].kiov_offset;
674
675                         csum = ksocknal_csum(csum, base, tx->tx_kiov[i].kiov_len);
676
677                         kunmap(tx->tx_kiov[i].kiov_page);
678                 }
679         } else {
680                 for (i = 1; i < tx->tx_niov; i++)
681                         csum = ksocknal_csum(csum, tx->tx_iov[i].iov_base,
682                                              tx->tx_iov[i].iov_len);
683         }
684
685         if (*ksocknal_tunables.ksnd_inject_csum_error) {
686                 csum++;
687                 *ksocknal_tunables.ksnd_inject_csum_error = 0;
688         }
689
690         tx->tx_msg.ksm_csum = csum;
691 }
692
693 int
694 ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle)
695 {
696         mm_segment_t   oldmm = get_fs ();
697         struct socket *sock = conn->ksnc_sock;
698         int            len;
699         int            rc;
700
701         rc = ksocknal_connsock_addref(conn);
702         if (rc != 0) {
703                 LASSERT (conn->ksnc_closing);
704                 *txmem = *rxmem = *nagle = 0;
705                 return (-ESHUTDOWN);
706         }
707
708         rc = libcfs_sock_getbuf(sock, txmem, rxmem);
709         if (rc == 0) {
710                 len = sizeof(*nagle);
711                 set_fs(KERNEL_DS);
712                 rc = sock->ops->getsockopt(sock, SOL_TCP, TCP_NODELAY,
713                                            (char *)nagle, &len);
714                 set_fs(oldmm);
715         }
716
717         ksocknal_connsock_decref(conn);
718
719         if (rc == 0)
720                 *nagle = !*nagle;
721         else
722                 *txmem = *rxmem = *nagle = 0;
723
724         return (rc);
725 }
726
727 int
728 ksocknal_lib_setup_sock (struct socket *sock)
729 {
730         mm_segment_t    oldmm = get_fs ();
731         int             rc;
732         int             option;
733         int             keep_idle;
734         int             keep_intvl;
735         int             keep_count;
736         int             do_keepalive;
737         struct linger   linger;
738
739         sock->sk->sk_allocation = GFP_NOFS;
740
741         /* Ensure this socket aborts active sends immediately when we close
742          * it. */
743
744         linger.l_onoff = 0;
745         linger.l_linger = 0;
746
747         set_fs (KERNEL_DS);
748         rc = sock_setsockopt (sock, SOL_SOCKET, SO_LINGER,
749                               (char *)&linger, sizeof (linger));
750         set_fs (oldmm);
751         if (rc != 0) {
752                 CERROR ("Can't set SO_LINGER: %d\n", rc);
753                 return (rc);
754         }
755
756         option = -1;
757         set_fs (KERNEL_DS);
758         rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_LINGER2,
759                                     (char *)&option, sizeof (option));
760         set_fs (oldmm);
761         if (rc != 0) {
762                 CERROR ("Can't set SO_LINGER2: %d\n", rc);
763                 return (rc);
764         }
765
766         if (!*ksocknal_tunables.ksnd_nagle) {
767                 option = 1;
768
769                 set_fs (KERNEL_DS);
770                 rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_NODELAY,
771                                             (char *)&option, sizeof (option));
772                 set_fs (oldmm);
773                 if (rc != 0) {
774                         CERROR ("Can't disable nagle: %d\n", rc);
775                         return (rc);
776                 }
777         }
778
779         rc = libcfs_sock_setbuf(sock,
780                                 *ksocknal_tunables.ksnd_tx_buffer_size,
781                                 *ksocknal_tunables.ksnd_rx_buffer_size);
782         if (rc != 0) {
783                 CERROR ("Can't set buffer tx %d, rx %d buffers: %d\n",
784                         *ksocknal_tunables.ksnd_tx_buffer_size,
785                         *ksocknal_tunables.ksnd_rx_buffer_size, rc);
786                 return (rc);
787         }
788
789 /* TCP_BACKOFF_* sockopt tunables unsupported in stock kernels */
790 #ifdef SOCKNAL_BACKOFF
791         if (*ksocknal_tunables.ksnd_backoff_init > 0) {
792                 option = *ksocknal_tunables.ksnd_backoff_init;
793
794                 set_fs (KERNEL_DS);
795                 rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_BACKOFF_INIT,
796                                             (char *)&option, sizeof (option));
797                 set_fs (oldmm);
798                 if (rc != 0) {
799                         CERROR ("Can't set initial tcp backoff %d: %d\n",
800                                 option, rc);
801                         return (rc);
802                 }
803         }
804
805         if (*ksocknal_tunables.ksnd_backoff_max > 0) {
806                 option = *ksocknal_tunables.ksnd_backoff_max;
807
808                 set_fs (KERNEL_DS);
809                 rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_BACKOFF_MAX,
810                                             (char *)&option, sizeof (option));
811                 set_fs (oldmm);
812                 if (rc != 0) {
813                         CERROR ("Can't set maximum tcp backoff %d: %d\n",
814                                 option, rc);
815                         return (rc);
816                 }
817         }
818 #endif
819
820         /* snapshot tunables */
821         keep_idle  = *ksocknal_tunables.ksnd_keepalive_idle;
822         keep_count = *ksocknal_tunables.ksnd_keepalive_count;
823         keep_intvl = *ksocknal_tunables.ksnd_keepalive_intvl;
824
825         do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0);
826
827         option = (do_keepalive ? 1 : 0);
828         set_fs (KERNEL_DS);
829         rc = sock_setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE,
830                               (char *)&option, sizeof (option));
831         set_fs (oldmm);
832         if (rc != 0) {
833                 CERROR ("Can't set SO_KEEPALIVE: %d\n", rc);
834                 return (rc);
835         }
836
837         if (!do_keepalive)
838                 return (0);
839
840         set_fs (KERNEL_DS);
841         rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPIDLE,
842                                     (char *)&keep_idle, sizeof (keep_idle));
843         set_fs (oldmm);
844         if (rc != 0) {
845                 CERROR ("Can't set TCP_KEEPIDLE: %d\n", rc);
846                 return (rc);
847         }
848
849         set_fs (KERNEL_DS);
850         rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPINTVL,
851                                     (char *)&keep_intvl, sizeof (keep_intvl));
852         set_fs (oldmm);
853         if (rc != 0) {
854                 CERROR ("Can't set TCP_KEEPINTVL: %d\n", rc);
855                 return (rc);
856         }
857
858         set_fs (KERNEL_DS);
859         rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPCNT,
860                                     (char *)&keep_count, sizeof (keep_count));
861         set_fs (oldmm);
862         if (rc != 0) {
863                 CERROR ("Can't set TCP_KEEPCNT: %d\n", rc);
864                 return (rc);
865         }
866
867         return (0);
868 }
869
870 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
871 struct tcp_opt *sock2tcp_opt(struct sock *sk)
872 {
873         return &(sk->tp_pinfo.af_tcp);
874 }
875 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10))
876 #define sock2tcp_opt(sk) tcp_sk(sk)
877 #else
878 struct tcp_opt *sock2tcp_opt(struct sock *sk)
879 {
880         struct tcp_sock *s = (struct tcp_sock *)sk;
881         return &s->tcp;
882 }
883 #endif
884
885 void
886 ksocknal_lib_push_conn (ksock_conn_t *conn)
887 {
888         struct sock    *sk;
889 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
890         struct tcp_opt *tp;
891 #else
892         struct tcp_sock *tp;
893 #endif
894         int             nonagle;
895         int             val = 1;
896         int             rc;
897         mm_segment_t    oldmm;
898
899         rc = ksocknal_connsock_addref(conn);
900         if (rc != 0)                            /* being shut down */
901                 return;
902
903         sk = conn->ksnc_sock->sk;
904         tp = sock2tcp_opt(sk);
905
906         lock_sock (sk);
907         nonagle = tp->nonagle;
908         tp->nonagle = 1;
909         release_sock (sk);
910
911         oldmm = get_fs ();
912         set_fs (KERNEL_DS);
913
914         rc = sk->sk_prot->setsockopt (sk, SOL_TCP, TCP_NODELAY,
915                                       (char *)&val, sizeof (val));
916         LASSERT (rc == 0);
917
918         set_fs (oldmm);
919
920         lock_sock (sk);
921         tp->nonagle = nonagle;
922         release_sock (sk);
923
924         ksocknal_connsock_decref(conn);
925 }
926
927 extern void ksocknal_read_callback (ksock_conn_t *conn);
928 extern void ksocknal_write_callback (ksock_conn_t *conn);
929 /*
930  * socket call back in Linux
931  */
932 static void
933 ksocknal_data_ready (struct sock *sk, int n)
934 {
935         ksock_conn_t  *conn;
936         ENTRY;
937
938         /* interleave correctly with closing sockets... */
939         LASSERT(!in_irq());
940         read_lock (&ksocknal_data.ksnd_global_lock);
941
942         conn = sk->sk_user_data;
943         if (conn == NULL) {             /* raced with ksocknal_terminate_conn */
944                 LASSERT (sk->sk_data_ready != &ksocknal_data_ready);
945                 sk->sk_data_ready (sk, n);
946         } else
947                 ksocknal_read_callback(conn);
948
949         read_unlock (&ksocknal_data.ksnd_global_lock);
950
951         EXIT;
952 }
953
954 static void
955 ksocknal_write_space (struct sock *sk)
956 {
957         ksock_conn_t  *conn;
958         int            wspace;
959         int            min_wpace;
960
961         /* interleave correctly with closing sockets... */
962         LASSERT(!in_irq());
963         read_lock (&ksocknal_data.ksnd_global_lock);
964
965         conn = sk->sk_user_data;
966         wspace = SOCKNAL_WSPACE(sk);
967         min_wpace = SOCKNAL_MIN_WSPACE(sk);
968
969         CDEBUG(D_NET, "sk %p wspace %d low water %d conn %p%s%s%s\n",
970                sk, wspace, min_wpace, conn,
971                (conn == NULL) ? "" : (conn->ksnc_tx_ready ?
972                                       " ready" : " blocked"),
973                (conn == NULL) ? "" : (conn->ksnc_tx_scheduled ?
974                                       " scheduled" : " idle"),
975                (conn == NULL) ? "" : (list_empty (&conn->ksnc_tx_queue) ?
976                                       " empty" : " queued"));
977
978         if (conn == NULL) {             /* raced with ksocknal_terminate_conn */
979                 LASSERT (sk->sk_write_space != &ksocknal_write_space);
980                 sk->sk_write_space (sk);
981
982                 read_unlock (&ksocknal_data.ksnd_global_lock);
983                 return;
984         }
985
986         if (wspace >= min_wpace) {              /* got enough space */
987                 ksocknal_write_callback(conn);
988
989                 /* Clear SOCK_NOSPACE _after_ ksocknal_write_callback so the
990                  * ENOMEM check in ksocknal_transmit is race-free (think about
991                  * it). */
992
993                 clear_bit (SOCK_NOSPACE, &sk->sk_socket->flags);
994         }
995
996         read_unlock (&ksocknal_data.ksnd_global_lock);
997 }
998
999 void
1000 ksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn)
1001 {
1002         conn->ksnc_saved_data_ready = sock->sk->sk_data_ready;
1003         conn->ksnc_saved_write_space = sock->sk->sk_write_space;
1004 }
1005
1006 void
1007 ksocknal_lib_set_callback(struct socket *sock,  ksock_conn_t *conn)
1008 {
1009         sock->sk->sk_user_data = conn;
1010         sock->sk->sk_data_ready = ksocknal_data_ready;
1011         sock->sk->sk_write_space = ksocknal_write_space;
1012         return;
1013 }
1014
1015 void
1016 ksocknal_lib_reset_callback(struct socket *sock, ksock_conn_t *conn)
1017 {
1018         /* Remove conn's network callbacks.
1019          * NB I _have_ to restore the callback, rather than storing a noop,
1020          * since the socket could survive past this module being unloaded!! */
1021         sock->sk->sk_data_ready = conn->ksnc_saved_data_ready;
1022         sock->sk->sk_write_space = conn->ksnc_saved_write_space;
1023
1024         /* A callback could be in progress already; they hold a read lock
1025          * on ksnd_global_lock (to serialise with me) and NOOP if
1026          * sk_user_data is NULL. */
1027         sock->sk->sk_user_data = NULL;
1028
1029         return ;
1030 }
1031