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