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