Whamcloud - gitweb
6ce7d030f2283c48ede6185a522f6d35373eeb76
[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
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
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
41 #ifndef HAVE_SYSCTL_UNNUMBERED
42
43 enum {
44         SOCKLND_TIMEOUT = 1,
45         SOCKLND_CREDITS,
46         SOCKLND_PEER_CREDITS,
47         SOCKLND_NCONNDS,
48         SOCKLND_RECONNECTS_MIN,
49         SOCKLND_RECONNECTS_MAX,
50         SOCKLND_EAGER_ACK,
51         SOCKLND_ZERO_COPY,
52         SOCKLND_TYPED,
53         SOCKLND_BULK_MIN,
54         SOCKLND_RX_BUFFER_SIZE,
55         SOCKLND_TX_BUFFER_SIZE,
56         SOCKLND_NAGLE,
57         SOCKLND_IRQ_AFFINITY,
58         SOCKLND_ROUND_ROBIN,
59         SOCKLND_KEEPALIVE,
60         SOCKLND_KEEPALIVE_IDLE,
61         SOCKLND_KEEPALIVE_COUNT,
62         SOCKLND_KEEPALIVE_INTVL,
63         SOCKLND_BACKOFF_INIT,
64         SOCKLND_BACKOFF_MAX,
65         SOCKLND_PROTOCOL,
66         SOCKLND_ZERO_COPY_RECV,
67         SOCKLND_ZERO_COPY_RECV_MIN_NFRAGS
68 };
69 #else
70
71 #define SOCKLND_TIMEOUT         CTL_UNNUMBERED
72 #define SOCKLND_CREDITS         CTL_UNNUMBERED
73 #define SOCKLND_PEER_CREDITS    CTL_UNNUMBERED
74 #define SOCKLND_NCONNDS         CTL_UNNUMBERED
75 #define SOCKLND_RECONNECTS_MIN  CTL_UNNUMBERED
76 #define SOCKLND_RECONNECTS_MAX  CTL_UNNUMBERED
77 #define SOCKLND_EAGER_ACK       CTL_UNNUMBERED
78 #define SOCKLND_ZERO_COPY       CTL_UNNUMBERED
79 #define SOCKLND_TYPED           CTL_UNNUMBERED
80 #define SOCKLND_BULK_MIN        CTL_UNNUMBERED
81 #define SOCKLND_RX_BUFFER_SIZE  CTL_UNNUMBERED
82 #define SOCKLND_TX_BUFFER_SIZE  CTL_UNNUMBERED
83 #define SOCKLND_NAGLE           CTL_UNNUMBERED
84 #define SOCKLND_IRQ_AFFINITY    CTL_UNNUMBERED
85 #define SOCKLND_ROUND_ROBIN     CTL_UNNUMBERED
86 #define SOCKLND_KEEPALIVE       CTL_UNNUMBERED
87 #define SOCKLND_KEEPALIVE_IDLE  CTL_UNNUMBERED
88 #define SOCKLND_KEEPALIVE_COUNT CTL_UNNUMBERED
89 #define SOCKLND_KEEPALIVE_INTVL CTL_UNNUMBERED
90 #define SOCKLND_BACKOFF_INIT    CTL_UNNUMBERED
91 #define SOCKLND_BACKOFF_MAX     CTL_UNNUMBERED
92 #define SOCKLND_PROTOCOL        CTL_UNNUMBERED
93 #define SOCKLND_ZERO_COPY_RECV  CTL_UNNUMBERED
94 #define SOCKLND_ZERO_COPY_RECV_MIN_NFRAGS CTL_UNNUMBERED
95 #endif
96
97 static cfs_sysctl_table_t ksocknal_ctl_table[] = {
98         {
99                 .ctl_name = SOCKLND_TIMEOUT,
100                 .procname = "timeout",
101                 .data     = &ksocknal_tunables.ksnd_timeout,
102                 .maxlen   = sizeof (int),
103                 .mode     = 0644,
104                 .proc_handler = &proc_dointvec,
105                 .strategy = &sysctl_intvec,
106         },
107         {
108                 .ctl_name = SOCKLND_CREDITS,
109                 .procname = "credits",
110                 .data     = &ksocknal_tunables.ksnd_credits,
111                 .maxlen   = sizeof (int),
112                 .mode     = 0444,
113                 .proc_handler = &proc_dointvec,
114                 .strategy = &sysctl_intvec,
115         },
116          {
117                 .ctl_name = SOCKLND_PEER_CREDITS,
118                 .procname = "peer_credits",
119                 .data     = &ksocknal_tunables.ksnd_peercredits,
120                 .maxlen   = sizeof (int),
121                 .mode     = 0444,
122                 .proc_handler = &proc_dointvec,
123                 .strategy = &sysctl_intvec,
124         },
125         {
126                 .ctl_name = SOCKLND_NCONNDS,
127                 .procname = "nconnds",
128                 .data     = &ksocknal_tunables.ksnd_nconnds,
129                 .maxlen   = sizeof (int),
130                 .mode     = 0444,
131                 .proc_handler = &proc_dointvec,
132                 .strategy = &sysctl_intvec,
133         },
134         {
135                 .ctl_name = SOCKLND_RECONNECTS_MIN,
136                 .procname = "min_reconnectms",
137                 .data     = &ksocknal_tunables.ksnd_min_reconnectms,
138                 .maxlen   = sizeof (int),
139                 .mode     = 0444,
140                 .proc_handler = &proc_dointvec,
141                 .strategy = &sysctl_intvec,
142         },
143         {
144                 .ctl_name = SOCKLND_RECONNECTS_MAX,
145                 .procname = "max_reconnectms",
146                 .data     = &ksocknal_tunables.ksnd_max_reconnectms,
147                 .maxlen   = sizeof (int),
148                 .mode     = 0444,
149                 .proc_handler = &proc_dointvec,
150                 .strategy = &sysctl_intvec,
151         },
152         {
153                 .ctl_name = SOCKLND_EAGER_ACK,
154                 .procname = "eager_ack",
155                 .data     = &ksocknal_tunables.ksnd_eager_ack,
156                 .maxlen   = sizeof (int),
157                 .mode     = 0644,
158                 .proc_handler = &proc_dointvec,
159                 .strategy = &sysctl_intvec,
160         },
161         {
162                 .ctl_name = SOCKLND_ZERO_COPY,
163                 .procname = "zero_copy",
164                 .data     = &ksocknal_tunables.ksnd_zc_min_payload,
165                 .maxlen   = sizeof (int),
166                 .mode     = 0644,
167                 .proc_handler = &proc_dointvec,
168                 .strategy = &sysctl_intvec,
169         },
170         {
171                 .ctl_name = SOCKLND_ZERO_COPY_RECV,
172                 .procname = "zero_copy_recv",
173                 .data     = &ksocknal_tunables.ksnd_zc_recv,
174                 .maxlen   = sizeof (int),
175                 .mode     = 0644,
176                 .proc_handler = &proc_dointvec,
177                 .strategy = &sysctl_intvec,
178         },
179
180         {
181                 .ctl_name = SOCKLND_ZERO_COPY_RECV_MIN_NFRAGS,
182                 .procname = "zero_copy_recv",
183                 .data     = &ksocknal_tunables.ksnd_zc_recv_min_nfrags,
184                 .maxlen   = sizeof (int),
185                 .mode     = 0644,
186                 .proc_handler = &proc_dointvec,
187                 .strategy = &sysctl_intvec,
188         },
189         {
190                 .ctl_name = SOCKLND_TYPED,
191                 .procname = "typed",
192                 .data     = &ksocknal_tunables.ksnd_typed_conns,
193                 .maxlen   = sizeof (int),
194                 .mode     = 0444,
195                 .proc_handler = &proc_dointvec,
196                 .strategy = &sysctl_intvec,
197         },
198         {
199                 .ctl_name = SOCKLND_BULK_MIN,
200                 .procname = "min_bulk",
201                 .data     = &ksocknal_tunables.ksnd_min_bulk,
202                 .maxlen   = sizeof (int),
203                 .mode     = 0644,
204                 .proc_handler = &proc_dointvec,
205                 .strategy = &sysctl_intvec,
206         },
207         {
208                 .ctl_name = SOCKLND_RX_BUFFER_SIZE,
209                 .procname = "rx_buffer_size",
210                 .data     = &ksocknal_tunables.ksnd_rx_buffer_size,
211                 .maxlen   = sizeof(int),
212                 .mode     = 0644,
213                 .proc_handler = &proc_dointvec,
214                 .strategy = &sysctl_intvec,
215         },
216         {
217                 .ctl_name = SOCKLND_TX_BUFFER_SIZE,
218                 .procname = "tx_buffer_size",
219                 .data     = &ksocknal_tunables.ksnd_tx_buffer_size,
220                 .maxlen   = sizeof(int),
221                 .mode     = 0644,
222                 .proc_handler = &proc_dointvec,
223                 .strategy = &sysctl_intvec,
224         },
225         {
226                 .ctl_name = SOCKLND_NAGLE,
227                 .procname = "nagle",
228                 .data     = &ksocknal_tunables.ksnd_nagle,
229                 .maxlen   = sizeof(int),
230                 .mode     = 0644,
231                 .proc_handler = &proc_dointvec,
232                 .strategy = &sysctl_intvec,
233         },
234 #ifdef CPU_AFFINITY
235         {
236                 .ctl_name = SOCKLND_IRQ_AFFINITY,
237                 .procname = "irq_affinity",
238                 .data     = &ksocknal_tunables.ksnd_irq_affinity,
239                 .maxlen   = sizeof(int),
240                 .mode     = 0644,
241                 .proc_handler = &proc_dointvec,
242                 .strategy = &sysctl_intvec,
243         },
244 #endif
245         {
246                 .ctl_name = SOCKLND_ROUND_ROBIN,
247                 .procname = "round_robin",
248                 .data     = &ksocknal_tunables.ksnd_round_robin,
249                 .maxlen   = sizeof(int),
250                 .mode     = 0644,
251                 .proc_handler = &proc_dointvec,
252                 .strategy = &sysctl_intvec,
253         },
254         {
255                 .ctl_name = SOCKLND_KEEPALIVE,
256                 .procname = "keepalive",
257                 .data     = &ksocknal_tunables.ksnd_keepalive,
258                 .maxlen   = sizeof(int),
259                 .mode     = 0644,
260                 .proc_handler = &proc_dointvec,
261                 .strategy = &sysctl_intvec,
262         },
263         {
264                 .ctl_name = SOCKLND_KEEPALIVE_IDLE,
265                 .procname = "keepalive_idle",
266                 .data     = &ksocknal_tunables.ksnd_keepalive_idle,
267                 .maxlen   = sizeof(int),
268                 .mode     = 0644,
269                 .proc_handler = &proc_dointvec,
270                 .strategy = &sysctl_intvec,
271         },
272         {
273                 .ctl_name = SOCKLND_KEEPALIVE_COUNT,
274                 .procname = "keepalive_count",
275                 .data     = &ksocknal_tunables.ksnd_keepalive_count,
276                 .maxlen   = sizeof(int),
277                 .mode     = 0644,
278                 .proc_handler = &proc_dointvec,
279                 .strategy = &sysctl_intvec,
280         },
281         {
282                 .ctl_name = SOCKLND_KEEPALIVE_INTVL,
283                 .procname = "keepalive_intvl",
284                 .data     = &ksocknal_tunables.ksnd_keepalive_intvl,
285                 .maxlen   = sizeof(int),
286                 .mode     = 0644,
287                 .proc_handler = &proc_dointvec,
288                 .strategy = &sysctl_intvec,
289         },
290 #ifdef SOCKNAL_BACKOFF
291         {
292                 .ctl_name = SOCKLND_BACKOFF_INIT,
293                 .procname = "backoff_init",
294                 .data     = &ksocknal_tunables.ksnd_backoff_init,
295                 .maxlen   = sizeof(int),
296                 .mode     = 0644,
297                 .proc_handler = &proc_dointvec,
298                 .strategy = &sysctl_intvec,
299         },
300         {
301                 .ctl_name = SOCKLND_BACKOFF_MAX,
302                 .procname = "backoff_max",
303                 .data     = &ksocknal_tunables.ksnd_backoff_max,
304                 .maxlen   = sizeof(int),
305                 .mode     = 0644,
306                 .proc_handler = &proc_dointvec,
307                 .strategy = &sysctl_intvec,
308         },
309 #endif
310 #if SOCKNAL_VERSION_DEBUG
311         {
312                 .ctl_name = SOCKLND_PROTOCOL,
313                 .procname = "protocol",
314                 .data     = &ksocknal_tunables.ksnd_protocol,
315                 .maxlen   = sizeof(int),
316                 .mode     = 0644,
317                 .proc_handler = &proc_dointvec,
318                 .strategy = &sysctl_intvec,
319         },
320 #endif
321         {0}
322 };
323
324
325 cfs_sysctl_table_t ksocknal_top_ctl_table[] = {
326         {
327                 .ctl_name = CTL_SOCKLND,
328                 .procname = "socknal",
329                 .data     = NULL,
330                 .maxlen   = 0,
331                 .mode     = 0555,
332                 .child    = ksocknal_ctl_table
333         },
334         { 0 }
335 };
336
337 int
338 ksocknal_lib_tunables_init ()
339 {
340         if (!*ksocknal_tunables.ksnd_typed_conns) {
341                 int rc = -EINVAL;
342 #if SOCKNAL_VERSION_DEBUG
343                 if (*ksocknal_tunables.ksnd_protocol < 3)
344                         rc = 0;
345 #endif
346                 if (rc != 0) {
347                         CERROR("Protocol V3.x MUST have typed connections\n");
348                         return rc;
349                 }
350         }
351
352         if (*ksocknal_tunables.ksnd_zc_recv_min_nfrags < 2)
353                 *ksocknal_tunables.ksnd_zc_recv_min_nfrags = 2;
354         if (*ksocknal_tunables.ksnd_zc_recv_min_nfrags > LNET_MAX_IOV)
355                 *ksocknal_tunables.ksnd_zc_recv_min_nfrags = LNET_MAX_IOV;
356
357         ksocknal_tunables.ksnd_sysctl =
358                 cfs_register_sysctl_table(ksocknal_top_ctl_table, 0);
359
360         if (ksocknal_tunables.ksnd_sysctl == NULL)
361                 CWARN("Can't setup /proc tunables\n");
362
363         return 0;
364 }
365
366 void
367 ksocknal_lib_tunables_fini ()
368 {
369         if (ksocknal_tunables.ksnd_sysctl != NULL)
370                 cfs_unregister_sysctl_table(ksocknal_tunables.ksnd_sysctl);
371 }
372 #else
373 int
374 ksocknal_lib_tunables_init ()
375 {
376         return 0;
377 }
378
379 void
380 ksocknal_lib_tunables_fini ()
381 {
382 }
383 #endif /* # if CONFIG_SYSCTL && !CFS_SYSFS_MODULE_PARM */
384
385 void
386 ksocknal_lib_bind_irq (unsigned int irq)
387 {
388 #if (defined(CONFIG_SMP) && defined(CPU_AFFINITY))
389         int              bind;
390         int              cpu;
391         char             cmdline[64];
392         ksock_irqinfo_t *info;
393         char            *argv[] = {"/bin/sh",
394                                    "-c",
395                                    cmdline,
396                                    NULL};
397         char            *envp[] = {"HOME=/",
398                                    "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
399                                    NULL};
400
401         LASSERT (irq < NR_IRQS);
402         if (irq == 0)              /* software NIC or affinity disabled */
403                 return;
404
405         info = &ksocknal_data.ksnd_irqinfo[irq];
406
407         cfs_write_lock_bh (&ksocknal_data.ksnd_global_lock);
408
409         LASSERT (info->ksni_valid);
410         bind = !info->ksni_bound;
411         info->ksni_bound = 1;
412
413         cfs_write_unlock_bh (&ksocknal_data.ksnd_global_lock);
414
415         if (!bind)                              /* bound already */
416                 return;
417
418         cpu = ksocknal_irqsched2cpu(info->ksni_sched);
419         snprintf (cmdline, sizeof (cmdline),
420                   "echo %d > /proc/irq/%u/smp_affinity", 1 << cpu, irq);
421
422         LCONSOLE_INFO("Binding irq %u to CPU %d with cmd: %s\n",
423                       irq, cpu, cmdline);
424
425         /* FIXME: Find a better method of setting IRQ affinity...
426          */
427
428         USERMODEHELPER(argv[0], argv, envp);
429 #endif
430 }
431
432 int
433 ksocknal_lib_get_conn_addrs (ksock_conn_t *conn)
434 {
435         int rc = libcfs_sock_getaddr(conn->ksnc_sock, 1,
436                                      &conn->ksnc_ipaddr,
437                                      &conn->ksnc_port);
438
439         /* Didn't need the {get,put}connsock dance to deref ksnc_sock... */
440         LASSERT (!conn->ksnc_closing);
441
442         if (rc != 0) {
443                 CERROR ("Error %d getting sock peer IP\n", rc);
444                 return rc;
445         }
446
447         rc = libcfs_sock_getaddr(conn->ksnc_sock, 0,
448                                  &conn->ksnc_myipaddr, NULL);
449         if (rc != 0) {
450                 CERROR ("Error %d getting sock local IP\n", rc);
451                 return rc;
452         }
453
454         return 0;
455 }
456
457 unsigned int
458 ksocknal_lib_sock_irq (struct socket *sock)
459 {
460         int                irq = 0;
461 #ifdef CPU_AFFINITY
462         struct dst_entry  *dst;
463
464         if (!*ksocknal_tunables.ksnd_irq_affinity)
465                 return 0;
466
467         dst = sk_dst_get (sock->sk);
468         if (dst != NULL) {
469                 if (dst->dev != NULL) {
470                         irq = dst->dev->irq;
471                         if (irq >= NR_IRQS) {
472                                 CERROR ("Unexpected IRQ %x\n", irq);
473                                 irq = 0;
474                         }
475                 }
476                 dst_release (dst);
477         }
478
479 #endif
480         return irq;
481 }
482
483 int
484 ksocknal_lib_zc_capable(ksock_conn_t *conn)
485 {
486         int  caps = conn->ksnc_sock->sk->sk_route_caps;
487
488         if (conn->ksnc_proto == &ksocknal_protocol_v1x)
489                 return 0;
490
491         /* ZC if the socket supports scatter/gather and doesn't need software
492          * checksums */
493         return ((caps & NETIF_F_SG) != 0 &&
494                 (caps & (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)) != 0);
495 }
496
497 int
498 ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
499 {
500         struct socket *sock = conn->ksnc_sock;
501         int            nob;
502         int            rc;
503
504         if (*ksocknal_tunables.ksnd_enable_csum        && /* checksum enabled */
505             conn->ksnc_proto == &ksocknal_protocol_v2x && /* V2.x connection  */
506             tx->tx_nob == tx->tx_resid                 && /* frist sending    */
507             tx->tx_msg.ksm_csum == 0)                     /* not checksummed  */
508                 ksocknal_lib_csum_tx(tx);
509
510         /* NB we can't trust socket ops to either consume our iovs
511          * or leave them alone. */
512
513         {
514 #if SOCKNAL_SINGLE_FRAG_TX
515                 struct iovec    scratch;
516                 struct iovec   *scratchiov = &scratch;
517                 unsigned int    niov = 1;
518 #else
519                 struct iovec   *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
520                 unsigned int    niov = tx->tx_niov;
521 #endif
522                 struct msghdr msg = {
523                         .msg_name       = NULL,
524                         .msg_namelen    = 0,
525                         .msg_iov        = scratchiov,
526                         .msg_iovlen     = niov,
527                         .msg_control    = NULL,
528                         .msg_controllen = 0,
529                         .msg_flags      = MSG_DONTWAIT
530                 };
531                 mm_segment_t oldmm = get_fs();
532                 int  i;
533
534                 for (nob = i = 0; i < niov; i++) {
535                         scratchiov[i] = tx->tx_iov[i];
536                         nob += scratchiov[i].iov_len;
537                 }
538
539                 if (!list_empty(&conn->ksnc_tx_queue) ||
540                     nob < tx->tx_resid)
541                         msg.msg_flags |= MSG_MORE;
542
543                 set_fs (KERNEL_DS);
544                 rc = sock_sendmsg(sock, &msg, nob);
545                 set_fs (oldmm);
546         }
547         return rc;
548 }
549
550 int
551 ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx)
552 {
553         struct socket *sock = conn->ksnc_sock;
554         lnet_kiov_t   *kiov = tx->tx_kiov;
555         int            rc;
556         int            nob;
557
558         /* Not NOOP message */
559         LASSERT (tx->tx_lnetmsg != NULL);
560
561         /* NB we can't trust socket ops to either consume our iovs
562          * or leave them alone. */
563         if (tx->tx_msg.ksm_zc_cookies[0] != 0) {
564                 /* Zero copy is enabled */
565                 struct sock   *sk = sock->sk;
566                 struct page   *page = kiov->kiov_page;
567                 int            offset = kiov->kiov_offset;
568                 int            fragsize = kiov->kiov_len;
569                 int            msgflg = MSG_DONTWAIT;
570
571                 CDEBUG(D_NET, "page %p + offset %x for %d\n",
572                                page, offset, kiov->kiov_len);
573
574                 if (!list_empty(&conn->ksnc_tx_queue) ||
575                     fragsize < tx->tx_resid)
576                         msgflg |= MSG_MORE;
577
578                 if (sk->sk_prot->sendpage != NULL) {
579                         rc = sk->sk_prot->sendpage(sk, page,
580                                                    offset, fragsize, msgflg);
581                 } else {
582                         rc = tcp_sendpage(sock, page, offset, fragsize, msgflg);
583                 }
584         } else {
585 #if SOCKNAL_SINGLE_FRAG_TX || !SOCKNAL_RISK_KMAP_DEADLOCK
586                 struct iovec  scratch;
587                 struct iovec *scratchiov = &scratch;
588                 unsigned int  niov = 1;
589 #else
590 #ifdef CONFIG_HIGHMEM
591 #warning "XXX risk of kmap deadlock on multiple frags..."
592 #endif
593                 struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
594                 unsigned int  niov = tx->tx_nkiov;
595 #endif
596                 struct msghdr msg = {
597                         .msg_name       = NULL,
598                         .msg_namelen    = 0,
599                         .msg_iov        = scratchiov,
600                         .msg_iovlen     = niov,
601                         .msg_control    = NULL,
602                         .msg_controllen = 0,
603                         .msg_flags      = MSG_DONTWAIT
604                 };
605                 mm_segment_t  oldmm = get_fs();
606                 int           i;
607
608                 for (nob = i = 0; i < niov; i++) {
609                         scratchiov[i].iov_base = kmap(kiov[i].kiov_page) +
610                                                  kiov[i].kiov_offset;
611                         nob += scratchiov[i].iov_len = kiov[i].kiov_len;
612                 }
613
614                 if (!list_empty(&conn->ksnc_tx_queue) ||
615                     nob < tx->tx_resid)
616                         msg.msg_flags |= MSG_MORE;
617
618                 set_fs (KERNEL_DS);
619                 rc = sock_sendmsg(sock, &msg, nob);
620                 set_fs (oldmm);
621
622                 for (i = 0; i < niov; i++)
623                         kunmap(kiov[i].kiov_page);
624         }
625         return rc;
626 }
627
628 void
629 ksocknal_lib_eager_ack (ksock_conn_t *conn)
630 {
631         int            opt = 1;
632         mm_segment_t   oldmm = get_fs();
633         struct socket *sock = conn->ksnc_sock;
634
635         /* Remind the socket to ACK eagerly.  If I don't, the socket might
636          * think I'm about to send something it could piggy-back the ACK
637          * on, introducing delay in completing zero-copy sends in my
638          * peer. */
639
640         set_fs(KERNEL_DS);
641         sock->ops->setsockopt (sock, SOL_TCP, TCP_QUICKACK,
642                                (char *)&opt, sizeof (opt));
643         set_fs(oldmm);
644 }
645
646 int
647 ksocknal_lib_recv_iov (ksock_conn_t *conn)
648 {
649 #if SOCKNAL_SINGLE_FRAG_RX
650         struct iovec  scratch;
651         struct iovec *scratchiov = &scratch;
652         unsigned int  niov = 1;
653 #else
654         struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
655         unsigned int  niov = conn->ksnc_rx_niov;
656 #endif
657         struct iovec *iov = conn->ksnc_rx_iov;
658         struct msghdr msg = {
659                 .msg_name       = NULL,
660                 .msg_namelen    = 0,
661                 .msg_iov        = scratchiov,
662                 .msg_iovlen     = niov,
663                 .msg_control    = NULL,
664                 .msg_controllen = 0,
665                 .msg_flags      = 0
666         };
667         mm_segment_t oldmm = get_fs();
668         int          nob;
669         int          i;
670         int          rc;
671         int          fragnob;
672         int          sum;
673         __u32        saved_csum;
674
675         /* NB we can't trust socket ops to either consume our iovs
676          * or leave them alone. */
677         LASSERT (niov > 0);
678
679         for (nob = i = 0; i < niov; i++) {
680                 scratchiov[i] = iov[i];
681                 nob += scratchiov[i].iov_len;
682         }
683         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
684
685         set_fs (KERNEL_DS);
686         rc = sock_recvmsg (conn->ksnc_sock, &msg, nob, MSG_DONTWAIT);
687         /* NB this is just a boolean..........................^ */
688         set_fs (oldmm);
689
690         saved_csum = 0;
691         if (conn->ksnc_proto == &ksocknal_protocol_v2x) {
692                 saved_csum = conn->ksnc_msg.ksm_csum;
693                 conn->ksnc_msg.ksm_csum = 0;
694         }
695
696         if (saved_csum != 0) {
697                 /* accumulate checksum */
698                 for (i = 0, sum = rc; sum > 0; i++, sum -= fragnob) {
699                         LASSERT (i < niov);
700
701                         fragnob = iov[i].iov_len;
702                         if (fragnob > sum)
703                                 fragnob = sum;
704
705                         conn->ksnc_rx_csum = ksocknal_csum(conn->ksnc_rx_csum,
706                                                            iov[i].iov_base, fragnob);
707                 }
708                 conn->ksnc_msg.ksm_csum = saved_csum;
709         }
710
711         return rc;
712 }
713
714 static void
715 ksocknal_lib_kiov_vunmap(void *addr)
716 {
717         if (addr == NULL)
718                 return;
719
720         vunmap(addr);
721 }
722
723 static void *
724 ksocknal_lib_kiov_vmap(lnet_kiov_t *kiov, int niov,
725                        struct iovec *iov, struct page **pages)
726 {
727         void             *addr;
728         int               nob;
729         int               i;
730
731         if (!*ksocknal_tunables.ksnd_zc_recv || pages == NULL)
732                 return NULL;
733
734         LASSERT (niov <= LNET_MAX_IOV);
735
736         if (niov < 2 ||
737             niov < *ksocknal_tunables.ksnd_zc_recv_min_nfrags)
738                 return NULL;
739
740         for (nob = i = 0; i < niov; i++) {
741                 if ((kiov[i].kiov_offset != 0 && i > 0) ||
742                     (kiov[i].kiov_offset + kiov[i].kiov_len != CFS_PAGE_SIZE && i < niov - 1))
743                         return NULL;
744
745                 pages[i] = kiov[i].kiov_page;
746                 nob += kiov[i].kiov_len;
747         }
748
749         addr = vmap(pages, niov, VM_MAP, PAGE_KERNEL);
750         if (addr == NULL)
751                 return NULL;
752
753         iov->iov_base = addr + kiov[0].kiov_offset;
754         iov->iov_len = nob;
755
756         return addr;
757 }
758
759 int
760 ksocknal_lib_recv_kiov (ksock_conn_t *conn)
761 {
762 #if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK
763         struct iovec   scratch;
764         struct iovec  *scratchiov = &scratch;
765         struct page  **pages      = NULL;
766         unsigned int   niov       = 1;
767 #else
768 #ifdef CONFIG_HIGHMEM
769 #warning "XXX risk of kmap deadlock on multiple frags..."
770 #endif
771         struct iovec  *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
772         struct page  **pages      = conn->ksnc_scheduler->kss_rx_scratch_pgs;
773         unsigned int   niov       = conn->ksnc_rx_nkiov;
774 #endif
775         lnet_kiov_t   *kiov = conn->ksnc_rx_kiov;
776         struct msghdr msg = {
777                 .msg_name       = NULL,
778                 .msg_namelen    = 0,
779                 .msg_iov        = scratchiov,
780                 .msg_control    = NULL,
781                 .msg_controllen = 0,
782                 .msg_flags      = 0
783         };
784         mm_segment_t oldmm = get_fs();
785         int          nob;
786         int          i;
787         int          rc;
788         void        *base;
789         void        *addr;
790         int          sum;
791         int          fragnob;
792
793         /* NB we can't trust socket ops to either consume our iovs
794          * or leave them alone. */
795         if ((addr = ksocknal_lib_kiov_vmap(kiov, niov, scratchiov, pages)) != NULL) {
796                 nob = scratchiov[0].iov_len;
797                 msg.msg_iovlen = 1;
798
799         } else {
800                 for (nob = i = 0; i < niov; i++) {
801                         nob += scratchiov[i].iov_len = kiov[i].kiov_len;
802                         scratchiov[i].iov_base = kmap(kiov[i].kiov_page) +
803                                                  kiov[i].kiov_offset;
804                 }
805                 msg.msg_iovlen = niov;
806         }
807
808         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
809
810         set_fs (KERNEL_DS);
811         rc = sock_recvmsg (conn->ksnc_sock, &msg, nob, MSG_DONTWAIT);
812         /* NB this is just a boolean.......................^ */
813         set_fs (oldmm);
814
815         if (conn->ksnc_msg.ksm_csum != 0) {
816                 for (i = 0, sum = rc; sum > 0; i++, sum -= fragnob) {
817                         LASSERT (i < niov);
818
819                         /* Dang! have to kmap again because I have nowhere to stash the
820                          * mapped address.  But by doing it while the page is still
821                          * mapped, the kernel just bumps the map count and returns me
822                          * the address it stashed. */
823                         base = kmap(kiov[i].kiov_page) + kiov[i].kiov_offset;
824                         fragnob = kiov[i].kiov_len;
825                         if (fragnob > sum)
826                                 fragnob = sum;
827
828                         conn->ksnc_rx_csum = ksocknal_csum(conn->ksnc_rx_csum,
829                                                            base, fragnob);
830
831                         kunmap(kiov[i].kiov_page);
832                 }
833         }
834
835         if (addr != NULL) {
836                 ksocknal_lib_kiov_vunmap(addr);
837         } else {
838                 for (i = 0; i < niov; i++)
839                         kunmap(kiov[i].kiov_page);
840         }
841
842         return (rc);
843 }
844
845 void
846 ksocknal_lib_csum_tx(ksock_tx_t *tx)
847 {
848         int          i;
849         __u32        csum;
850         void        *base;
851
852         LASSERT(tx->tx_iov[0].iov_base == (void *)&tx->tx_msg);
853         LASSERT(tx->tx_conn != NULL);
854         LASSERT(tx->tx_conn->ksnc_proto == &ksocknal_protocol_v2x);
855
856         tx->tx_msg.ksm_csum = 0;
857
858         csum = ksocknal_csum(~0, (void *)tx->tx_iov[0].iov_base,
859                              tx->tx_iov[0].iov_len);
860
861         if (tx->tx_kiov != NULL) {
862                 for (i = 0; i < tx->tx_nkiov; i++) {
863                         base = kmap(tx->tx_kiov[i].kiov_page) +
864                                tx->tx_kiov[i].kiov_offset;
865
866                         csum = ksocknal_csum(csum, base, tx->tx_kiov[i].kiov_len);
867
868                         kunmap(tx->tx_kiov[i].kiov_page);
869                 }
870         } else {
871                 for (i = 1; i < tx->tx_niov; i++)
872                         csum = ksocknal_csum(csum, tx->tx_iov[i].iov_base,
873                                              tx->tx_iov[i].iov_len);
874         }
875
876         if (*ksocknal_tunables.ksnd_inject_csum_error) {
877                 csum++;
878                 *ksocknal_tunables.ksnd_inject_csum_error = 0;
879         }
880
881         tx->tx_msg.ksm_csum = csum;
882 }
883
884 int
885 ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle)
886 {
887         mm_segment_t   oldmm = get_fs ();
888         struct socket *sock = conn->ksnc_sock;
889         int            len;
890         int            rc;
891
892         rc = ksocknal_connsock_addref(conn);
893         if (rc != 0) {
894                 LASSERT (conn->ksnc_closing);
895                 *txmem = *rxmem = *nagle = 0;
896                 return (-ESHUTDOWN);
897         }
898
899         rc = libcfs_sock_getbuf(sock, txmem, rxmem);
900         if (rc == 0) {
901                 len = sizeof(*nagle);
902                 set_fs(KERNEL_DS);
903                 rc = sock->ops->getsockopt(sock, SOL_TCP, TCP_NODELAY,
904                                            (char *)nagle, &len);
905                 set_fs(oldmm);
906         }
907
908         ksocknal_connsock_decref(conn);
909
910         if (rc == 0)
911                 *nagle = !*nagle;
912         else
913                 *txmem = *rxmem = *nagle = 0;
914
915         return (rc);
916 }
917
918 int
919 ksocknal_lib_setup_sock (struct socket *sock)
920 {
921         mm_segment_t    oldmm = get_fs ();
922         int             rc;
923         int             option;
924         int             keep_idle;
925         int             keep_intvl;
926         int             keep_count;
927         int             do_keepalive;
928         struct linger   linger;
929
930         sock->sk->sk_allocation = GFP_NOFS;
931
932         /* Ensure this socket aborts active sends immediately when we close
933          * it. */
934
935         linger.l_onoff = 0;
936         linger.l_linger = 0;
937
938         set_fs (KERNEL_DS);
939         rc = sock_setsockopt (sock, SOL_SOCKET, SO_LINGER,
940                               (char *)&linger, sizeof (linger));
941         set_fs (oldmm);
942         if (rc != 0) {
943                 CERROR ("Can't set SO_LINGER: %d\n", rc);
944                 return (rc);
945         }
946
947         option = -1;
948         set_fs (KERNEL_DS);
949         rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_LINGER2,
950                                     (char *)&option, sizeof (option));
951         set_fs (oldmm);
952         if (rc != 0) {
953                 CERROR ("Can't set SO_LINGER2: %d\n", rc);
954                 return (rc);
955         }
956
957         if (!*ksocknal_tunables.ksnd_nagle) {
958                 option = 1;
959
960                 set_fs (KERNEL_DS);
961                 rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_NODELAY,
962                                             (char *)&option, sizeof (option));
963                 set_fs (oldmm);
964                 if (rc != 0) {
965                         CERROR ("Can't disable nagle: %d\n", rc);
966                         return (rc);
967                 }
968         }
969
970         rc = libcfs_sock_setbuf(sock,
971                                 *ksocknal_tunables.ksnd_tx_buffer_size,
972                                 *ksocknal_tunables.ksnd_rx_buffer_size);
973         if (rc != 0) {
974                 CERROR ("Can't set buffer tx %d, rx %d buffers: %d\n",
975                         *ksocknal_tunables.ksnd_tx_buffer_size,
976                         *ksocknal_tunables.ksnd_rx_buffer_size, rc);
977                 return (rc);
978         }
979
980 /* TCP_BACKOFF_* sockopt tunables unsupported in stock kernels */
981 #ifdef SOCKNAL_BACKOFF
982         if (*ksocknal_tunables.ksnd_backoff_init > 0) {
983                 option = *ksocknal_tunables.ksnd_backoff_init;
984 #ifdef SOCKNAL_BACKOFF_MS
985                 option *= 1000;
986 #endif
987
988                 set_fs (KERNEL_DS);
989                 rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_BACKOFF_INIT,
990                                             (char *)&option, sizeof (option));
991                 set_fs (oldmm);
992                 if (rc != 0) {
993                         CERROR ("Can't set initial tcp backoff %d: %d\n",
994                                 option, rc);
995                         return (rc);
996                 }
997         }
998
999         if (*ksocknal_tunables.ksnd_backoff_max > 0) {
1000                 option = *ksocknal_tunables.ksnd_backoff_max;
1001 #ifdef SOCKNAL_BACKOFF_MS
1002                 option *= 1000;
1003 #endif
1004
1005                 set_fs (KERNEL_DS);
1006                 rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_BACKOFF_MAX,
1007                                             (char *)&option, sizeof (option));
1008                 set_fs (oldmm);
1009                 if (rc != 0) {
1010                         CERROR ("Can't set maximum tcp backoff %d: %d\n",
1011                                 option, rc);
1012                         return (rc);
1013                 }
1014         }
1015 #endif
1016
1017         /* snapshot tunables */
1018         keep_idle  = *ksocknal_tunables.ksnd_keepalive_idle;
1019         keep_count = *ksocknal_tunables.ksnd_keepalive_count;
1020         keep_intvl = *ksocknal_tunables.ksnd_keepalive_intvl;
1021
1022         do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0);
1023
1024         option = (do_keepalive ? 1 : 0);
1025         set_fs (KERNEL_DS);
1026         rc = sock_setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE,
1027                               (char *)&option, sizeof (option));
1028         set_fs (oldmm);
1029         if (rc != 0) {
1030                 CERROR ("Can't set SO_KEEPALIVE: %d\n", rc);
1031                 return (rc);
1032         }
1033
1034         if (!do_keepalive)
1035                 return (0);
1036
1037         set_fs (KERNEL_DS);
1038         rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPIDLE,
1039                                     (char *)&keep_idle, sizeof (keep_idle));
1040         set_fs (oldmm);
1041         if (rc != 0) {
1042                 CERROR ("Can't set TCP_KEEPIDLE: %d\n", rc);
1043                 return (rc);
1044         }
1045
1046         set_fs (KERNEL_DS);
1047         rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPINTVL,
1048                                     (char *)&keep_intvl, sizeof (keep_intvl));
1049         set_fs (oldmm);
1050         if (rc != 0) {
1051                 CERROR ("Can't set TCP_KEEPINTVL: %d\n", rc);
1052                 return (rc);
1053         }
1054
1055         set_fs (KERNEL_DS);
1056         rc = sock->ops->setsockopt (sock, SOL_TCP, TCP_KEEPCNT,
1057                                     (char *)&keep_count, sizeof (keep_count));
1058         set_fs (oldmm);
1059         if (rc != 0) {
1060                 CERROR ("Can't set TCP_KEEPCNT: %d\n", rc);
1061                 return (rc);
1062         }
1063
1064         return (0);
1065 }
1066
1067 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
1068 struct tcp_opt *sock2tcp_opt(struct sock *sk)
1069 {
1070         return &(sk->tp_pinfo.af_tcp);
1071 }
1072 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10))
1073 #define sock2tcp_opt(sk) tcp_sk(sk)
1074 #else
1075 struct tcp_opt *sock2tcp_opt(struct sock *sk)
1076 {
1077         struct tcp_sock *s = (struct tcp_sock *)sk;
1078         return &s->tcp;
1079 }
1080 #endif
1081
1082 void
1083 ksocknal_lib_push_conn (ksock_conn_t *conn)
1084 {
1085         struct sock    *sk;
1086 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
1087         struct tcp_opt *tp;
1088 #else
1089         struct tcp_sock *tp;
1090 #endif
1091         int             nonagle;
1092         int             val = 1;
1093         int             rc;
1094         mm_segment_t    oldmm;
1095
1096         rc = ksocknal_connsock_addref(conn);
1097         if (rc != 0)                            /* being shut down */
1098                 return;
1099
1100         sk = conn->ksnc_sock->sk;
1101         tp = sock2tcp_opt(sk);
1102
1103         lock_sock (sk);
1104         nonagle = tp->nonagle;
1105         tp->nonagle = 1;
1106         release_sock (sk);
1107
1108         oldmm = get_fs ();
1109         set_fs (KERNEL_DS);
1110
1111         rc = sk->sk_prot->setsockopt (sk, SOL_TCP, TCP_NODELAY,
1112                                       (char *)&val, sizeof (val));
1113         LASSERT (rc == 0);
1114
1115         set_fs (oldmm);
1116
1117         lock_sock (sk);
1118         tp->nonagle = nonagle;
1119         release_sock (sk);
1120
1121         ksocknal_connsock_decref(conn);
1122 }
1123
1124 extern void ksocknal_read_callback (ksock_conn_t *conn);
1125 extern void ksocknal_write_callback (ksock_conn_t *conn);
1126 /*
1127  * socket call back in Linux
1128  */
1129 static void
1130 ksocknal_data_ready (struct sock *sk, int n)
1131 {
1132         ksock_conn_t  *conn;
1133         ENTRY;
1134
1135         /* interleave correctly with closing sockets... */
1136         LASSERT(!in_irq());
1137         cfs_read_lock (&ksocknal_data.ksnd_global_lock);
1138
1139         conn = sk->sk_user_data;
1140         if (conn == NULL) {             /* raced with ksocknal_terminate_conn */
1141                 LASSERT (sk->sk_data_ready != &ksocknal_data_ready);
1142                 sk->sk_data_ready (sk, n);
1143         } else
1144                 ksocknal_read_callback(conn);
1145
1146         cfs_read_unlock (&ksocknal_data.ksnd_global_lock);
1147
1148         EXIT;
1149 }
1150
1151 static void
1152 ksocknal_write_space (struct sock *sk)
1153 {
1154         ksock_conn_t  *conn;
1155         int            wspace;
1156         int            min_wpace;
1157
1158         /* interleave correctly with closing sockets... */
1159         LASSERT(!in_irq());
1160         cfs_read_lock (&ksocknal_data.ksnd_global_lock);
1161
1162         conn = sk->sk_user_data;
1163         wspace = SOCKNAL_WSPACE(sk);
1164         min_wpace = SOCKNAL_MIN_WSPACE(sk);
1165
1166         CDEBUG(D_NET, "sk %p wspace %d low water %d conn %p%s%s%s\n",
1167                sk, wspace, min_wpace, conn,
1168                (conn == NULL) ? "" : (conn->ksnc_tx_ready ?
1169                                       " ready" : " blocked"),
1170                (conn == NULL) ? "" : (conn->ksnc_tx_scheduled ?
1171                                       " scheduled" : " idle"),
1172                (conn == NULL) ? "" : (list_empty (&conn->ksnc_tx_queue) ?
1173                                       " empty" : " queued"));
1174
1175         if (conn == NULL) {             /* raced with ksocknal_terminate_conn */
1176                 LASSERT (sk->sk_write_space != &ksocknal_write_space);
1177                 sk->sk_write_space (sk);
1178
1179                 cfs_read_unlock (&ksocknal_data.ksnd_global_lock);
1180                 return;
1181         }
1182
1183         if (wspace >= min_wpace) {              /* got enough space */
1184                 ksocknal_write_callback(conn);
1185
1186                 /* Clear SOCK_NOSPACE _after_ ksocknal_write_callback so the
1187                  * ENOMEM check in ksocknal_transmit is race-free (think about
1188                  * it). */
1189
1190                 clear_bit (SOCK_NOSPACE, &sk->sk_socket->flags);
1191         }
1192
1193         cfs_read_unlock (&ksocknal_data.ksnd_global_lock);
1194 }
1195
1196 void
1197 ksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn)
1198 {
1199         conn->ksnc_saved_data_ready = sock->sk->sk_data_ready;
1200         conn->ksnc_saved_write_space = sock->sk->sk_write_space;
1201 }
1202
1203 void
1204 ksocknal_lib_set_callback(struct socket *sock,  ksock_conn_t *conn)
1205 {
1206         sock->sk->sk_user_data = conn;
1207         sock->sk->sk_data_ready = ksocknal_data_ready;
1208         sock->sk->sk_write_space = ksocknal_write_space;
1209         return;
1210 }
1211
1212 void
1213 ksocknal_lib_reset_callback(struct socket *sock, ksock_conn_t *conn)
1214 {
1215         /* Remove conn's network callbacks.
1216          * NB I _have_ to restore the callback, rather than storing a noop,
1217          * since the socket could survive past this module being unloaded!! */
1218         sock->sk->sk_data_ready = conn->ksnc_saved_data_ready;
1219         sock->sk->sk_write_space = conn->ksnc_saved_write_space;
1220
1221         /* A callback could be in progress already; they hold a read lock
1222          * on ksnd_global_lock (to serialise with me) and NOOP if
1223          * sk_user_data is NULL. */
1224         sock->sk->sk_user_data = NULL;
1225
1226         return ;
1227 }
1228
1229 int
1230 ksocknal_lib_memory_pressure(ksock_conn_t *conn)
1231 {
1232         int            rc = 0;
1233         ksock_sched_t *sched;
1234         
1235         sched = conn->ksnc_scheduler;
1236         cfs_spin_lock_bh (&sched->kss_lock);
1237         
1238         if (!SOCK_TEST_NOSPACE(conn->ksnc_sock) &&
1239             !conn->ksnc_tx_ready) {
1240                 /* SOCK_NOSPACE is set when the socket fills
1241                  * and cleared in the write_space callback
1242                  * (which also sets ksnc_tx_ready).  If
1243                  * SOCK_NOSPACE and ksnc_tx_ready are BOTH
1244                  * zero, I didn't fill the socket and
1245                  * write_space won't reschedule me, so I
1246                  * return -ENOMEM to get my caller to retry
1247                  * after a timeout */
1248                 rc = -ENOMEM;
1249         }
1250         
1251         cfs_spin_unlock_bh (&sched->kss_lock);
1252
1253         return rc;
1254 }
1255
1256 __u64
1257 ksocknal_lib_new_incarnation(void)
1258 {
1259         struct timeval tv;
1260
1261         /* The incarnation number is the time this module loaded and it
1262          * identifies this particular instance of the socknal.  Hopefully
1263          * we won't be able to reboot more frequently than 1MHz for the
1264          * forseeable future :) */
1265
1266         do_gettimeofday(&tv);
1267
1268         return (((__u64)tv.tv_sec) * 1000000) + tv.tv_usec;
1269 }
1270
1271 int
1272 ksocknal_lib_bind_thread_to_cpu(int id)
1273 {
1274 #if defined(CONFIG_SMP) && defined(CPU_AFFINITY)
1275         id = ksocknal_sched2cpu(id);
1276         if (cpu_online(id)) {
1277                 cpumask_t m = CPU_MASK_NONE;
1278                 cpu_set(id, m);
1279                 set_cpus_allowed(current, m);
1280                 return 0;
1281         }
1282
1283         return -1;
1284
1285 #else
1286         return 0;
1287 #endif
1288 }