+ sock_release(as->ibas_sock);
+ PORTAL_FREE(as, sizeof(*as));
+}
+
+int
+kibnal_ip_listener(void *arg)
+{
+ struct sockaddr_in addr;
+ wait_queue_t wait;
+ struct socket *sock;
+ kib_acceptsock_t *as;
+ int port;
+ char name[16];
+ int rc;
+ unsigned long flags;
+
+ /* Parent thread holds kib_nid_mutex, and is, or is about to
+ * block on kib_listener_signal */
+
+ port = kibnal_tunables.kib_port;
+ snprintf(name, sizeof(name), "kibnal_lstn%03d", port);
+ kportal_daemonize(name);
+ kportal_blockallsigs();
+
+ init_waitqueue_entry(&wait, current);
+
+ rc = kibnal_create_sock(&sock);
+ if (rc != 0)
+ goto out_0;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ rc = sock->ops->bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+ if (rc != 0) {
+ CERROR("Can't bind to port %d\n", port);
+ goto out_1;
+ }
+
+ rc = sock->ops->listen(sock, kibnal_tunables.kib_backlog);
+ if (rc != 0) {
+ CERROR("Can't set listen backlog %d: %d\n",
+ kibnal_tunables.kib_backlog, rc);
+ goto out_1;
+ }
+
+ LASSERT (kibnal_data.kib_listener_sock == NULL);
+ kibnal_data.kib_listener_sock = sock;
+
+ /* unblock waiting parent */
+ LASSERT (kibnal_data.kib_listener_shutdown == 0);
+ up(&kibnal_data.kib_listener_signal);
+
+ /* Wake me any time something happens on my socket */
+ add_wait_queue(sock->sk->sk_sleep, &wait);
+ as = NULL;
+
+ while (kibnal_data.kib_listener_shutdown == 0) {
+
+ if (as == NULL) {
+ PORTAL_ALLOC(as, sizeof(*as));
+ if (as == NULL) {
+ CERROR("Out of Memory: pausing...\n");
+ kibnal_pause(HZ);
+ continue;
+ }
+ as->ibas_sock = NULL;
+ }
+
+ if (as->ibas_sock == NULL) {
+ as->ibas_sock = sock_alloc();
+ if (as->ibas_sock == NULL) {
+ CERROR("Can't allocate socket: pausing...\n");
+ kibnal_pause(HZ);
+ continue;
+ }
+ /* XXX this should add a ref to sock->ops->owner, if
+ * TCP could be a module */
+ as->ibas_sock->type = sock->type;
+ as->ibas_sock->ops = sock->ops;
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ rc = sock->ops->accept(sock, as->ibas_sock, O_NONBLOCK);
+
+ /* Sleep for socket activity? */
+ if (rc == -EAGAIN &&
+ kibnal_data.kib_listener_shutdown == 0)
+ schedule();
+
+ set_current_state(TASK_RUNNING);
+
+ if (rc == 0) {
+ spin_lock_irqsave(&kibnal_data.kib_connd_lock, flags);
+
+ list_add_tail(&as->ibas_list,
+ &kibnal_data.kib_connd_acceptq);
+
+ spin_unlock_irqrestore(&kibnal_data.kib_connd_lock, flags);
+ wake_up(&kibnal_data.kib_connd_waitq);
+
+ as = NULL;
+ continue;
+ }
+
+ if (rc != -EAGAIN) {
+ CERROR("Accept failed: %d, pausing...\n", rc);
+ kibnal_pause(HZ);
+ }
+ }
+
+ if (as != NULL) {
+ if (as->ibas_sock != NULL)
+ sock_release(as->ibas_sock);
+ PORTAL_FREE(as, sizeof(*as));
+ }
+
+ rc = 0;
+ remove_wait_queue(sock->sk->sk_sleep, &wait);
+ out_1:
+ sock_release(sock);
+ kibnal_data.kib_listener_sock = NULL;
+ out_0:
+ /* set completion status and unblock thread waiting for me
+ * (parent on startup failure, executioner on normal shutdown) */
+ kibnal_data.kib_listener_shutdown = rc;
+ up(&kibnal_data.kib_listener_signal);
+
+ return 0;
+}
+
+int
+kibnal_start_ip_listener (void)
+{
+ long pid;
+ int rc;
+
+ CDEBUG(D_WARNING, "Starting listener\n");