Skip to content
Snippets Groups Projects
lowcomms-tcp.c 26.8 KiB
Newer Older
		if (read_list_empty())
			schedule();
		set_current_state(TASK_RUNNING);

		process_sockets();
	}

	return 0;
}

static int write_and_state_lists_empty(void)
{
	int status;

	spin_lock_bh(&write_sockets_lock);
	status = list_empty(&write_sockets);
	spin_unlock_bh(&write_sockets_lock);

	spin_lock_bh(&state_sockets_lock);
	if (list_empty(&state_sockets) == 0)
		status = 0;
	spin_unlock_bh(&state_sockets_lock);

	return status;
}

/* DLM Transport send daemon */
static int dlm_sendd(void *data)
{
	init_waitqueue_entry(&lowcomms_send_waitq_head, current);
	add_wait_queue(&lowcomms_send_waitq, &lowcomms_send_waitq_head);

	while (!kthread_should_stop()) {
		set_current_state(TASK_INTERRUPTIBLE);
		if (write_and_state_lists_empty())
			schedule();
		set_current_state(TASK_RUNNING);

		process_state_queue();
		process_output_queue();
	}

	return 0;
}

static void daemons_stop(void)
{
	kthread_stop(recv_task);
	kthread_stop(send_task);
}

static int daemons_start(void)
{
	struct task_struct *p;
	int error;

	p = kthread_run(dlm_recvd, NULL, "dlm_recvd");
	error = IS_ERR(p);
	if (error) {
		log_print("can't start dlm_recvd %d", error);
		return error;
	}
	recv_task = p;

	p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
	error = IS_ERR(p);
	if (error) {
		log_print("can't start dlm_sendd %d", error);
		kthread_stop(recv_task);
		return error;
	}
	send_task = p;

	return 0;
}

void dlm_lowcomms_stop(void)
{
	int i;

	/* Set all the flags to prevent any
	   socket activity.
	*/
	for (i = 0; i < conn_array_size; i++) {
		if (connections[i])
			connections[i]->flags |= 0xFF;
	daemons_stop();
	clean_writequeues();

	for (i = 0; i < conn_array_size; i++) {
		if (connections[i]) {
			close_connection(connections[i], true);
			if (connections[i]->othercon)
				kmem_cache_free(con_cache, connections[i]->othercon);
			kmem_cache_free(con_cache, connections[i]);
		}
	}

	kfree(connections);
	connections = NULL;

	kmem_cache_destroy(con_cache);
}

/* This is quite likely to sleep... */
int dlm_lowcomms_start(void)
{
	int error = 0;

	error = -ENOMEM;
	connections = kzalloc(sizeof(struct connection *) *
			      NODE_INCREMENT, GFP_KERNEL);
	if (!connections)
		goto out;

	conn_array_size = NODE_INCREMENT;

	if (dlm_our_addr(&dlm_local_addr, 0)) {
		log_print("no local IP address has been set");
		goto fail_free_conn;
	}
	if (!dlm_our_addr(&dlm_local_addr, 1)) {
		log_print("This dlm comms module does not support multi-homed clustering");
		goto fail_free_conn;
	}

	con_cache = kmem_cache_create("dlm_conn", sizeof(struct connection),
				      __alignof__(struct connection), 0,
				      NULL, NULL);
	if (!con_cache)
		goto fail_free_conn;


	/* Start listening */
	error = listen_for_all();
	if (error)
		goto fail_unlisten;

	error = daemons_start();
	if (error)
		goto fail_unlisten;

	return 0;

fail_unlisten:
	close_connection(connections[0], false);
	kmem_cache_free(con_cache, connections[0]);
	kmem_cache_destroy(con_cache);

fail_free_conn:
	return error;
}

/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * Emacs will notice this stuff at the end of the file and automatically
 * adjust the settings for this buffer only.  This must remain at the end
 * of the file.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-file-style: "linux"
 * End:
 */