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