Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm: dlm: sanitize work_start() in lowcomms.c dlm: reduce cond_resched during send dlm: use TCP_NODELAY dlm: Use cmwq for send and receive workqueues dlm: Handle application limited situations properly.
This commit is contained in:
commit
f9f265f355
1 changed files with 50 additions and 13 deletions
|
@ -63,6 +63,9 @@
|
||||||
#define NEEDED_RMEM (4*1024*1024)
|
#define NEEDED_RMEM (4*1024*1024)
|
||||||
#define CONN_HASH_SIZE 32
|
#define CONN_HASH_SIZE 32
|
||||||
|
|
||||||
|
/* Number of messages to send before rescheduling */
|
||||||
|
#define MAX_SEND_MSG_COUNT 25
|
||||||
|
|
||||||
struct cbuf {
|
struct cbuf {
|
||||||
unsigned int base;
|
unsigned int base;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
@ -108,6 +111,7 @@ struct connection {
|
||||||
#define CF_INIT_PENDING 4
|
#define CF_INIT_PENDING 4
|
||||||
#define CF_IS_OTHERCON 5
|
#define CF_IS_OTHERCON 5
|
||||||
#define CF_CLOSE 6
|
#define CF_CLOSE 6
|
||||||
|
#define CF_APP_LIMITED 7
|
||||||
struct list_head writequeue; /* List of outgoing writequeue_entries */
|
struct list_head writequeue; /* List of outgoing writequeue_entries */
|
||||||
spinlock_t writequeue_lock;
|
spinlock_t writequeue_lock;
|
||||||
int (*rx_action) (struct connection *); /* What to do when active */
|
int (*rx_action) (struct connection *); /* What to do when active */
|
||||||
|
@ -295,7 +299,17 @@ static void lowcomms_write_space(struct sock *sk)
|
||||||
{
|
{
|
||||||
struct connection *con = sock2con(sk);
|
struct connection *con = sock2con(sk);
|
||||||
|
|
||||||
if (con && !test_and_set_bit(CF_WRITE_PENDING, &con->flags))
|
if (!con)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clear_bit(SOCK_NOSPACE, &con->sock->flags);
|
||||||
|
|
||||||
|
if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) {
|
||||||
|
con->sock->sk->sk_write_pending--;
|
||||||
|
clear_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
|
||||||
queue_work(send_workqueue, &con->swork);
|
queue_work(send_workqueue, &con->swork);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,6 +929,7 @@ static void tcp_connect_to_sock(struct connection *con)
|
||||||
struct sockaddr_storage saddr, src_addr;
|
struct sockaddr_storage saddr, src_addr;
|
||||||
int addr_len;
|
int addr_len;
|
||||||
struct socket *sock = NULL;
|
struct socket *sock = NULL;
|
||||||
|
int one = 1;
|
||||||
|
|
||||||
if (con->nodeid == 0) {
|
if (con->nodeid == 0) {
|
||||||
log_print("attempt to connect sock 0 foiled");
|
log_print("attempt to connect sock 0 foiled");
|
||||||
|
@ -960,6 +975,11 @@ static void tcp_connect_to_sock(struct connection *con)
|
||||||
make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len);
|
make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len);
|
||||||
|
|
||||||
log_print("connecting to %d", con->nodeid);
|
log_print("connecting to %d", con->nodeid);
|
||||||
|
|
||||||
|
/* Turn off Nagle's algorithm */
|
||||||
|
kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one,
|
||||||
|
sizeof(one));
|
||||||
|
|
||||||
result =
|
result =
|
||||||
sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
|
sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
|
||||||
O_NONBLOCK);
|
O_NONBLOCK);
|
||||||
|
@ -1011,6 +1031,10 @@ static struct socket *tcp_create_listen_sock(struct connection *con,
|
||||||
goto create_out;
|
goto create_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Turn off Nagle's algorithm */
|
||||||
|
kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one,
|
||||||
|
sizeof(one));
|
||||||
|
|
||||||
result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
||||||
(char *)&one, sizeof(one));
|
(char *)&one, sizeof(one));
|
||||||
|
|
||||||
|
@ -1297,6 +1321,7 @@ static void send_to_sock(struct connection *con)
|
||||||
const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
|
const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
|
||||||
struct writequeue_entry *e;
|
struct writequeue_entry *e;
|
||||||
int len, offset;
|
int len, offset;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
mutex_lock(&con->sock_mutex);
|
mutex_lock(&con->sock_mutex);
|
||||||
if (con->sock == NULL)
|
if (con->sock == NULL)
|
||||||
|
@ -1319,14 +1344,27 @@ static void send_to_sock(struct connection *con)
|
||||||
ret = kernel_sendpage(con->sock, e->page, offset, len,
|
ret = kernel_sendpage(con->sock, e->page, offset, len,
|
||||||
msg_flags);
|
msg_flags);
|
||||||
if (ret == -EAGAIN || ret == 0) {
|
if (ret == -EAGAIN || ret == 0) {
|
||||||
|
if (ret == -EAGAIN &&
|
||||||
|
test_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags) &&
|
||||||
|
!test_and_set_bit(CF_APP_LIMITED, &con->flags)) {
|
||||||
|
/* Notify TCP that we're limited by the
|
||||||
|
* application window size.
|
||||||
|
*/
|
||||||
|
set_bit(SOCK_NOSPACE, &con->sock->flags);
|
||||||
|
con->sock->sk->sk_write_pending++;
|
||||||
|
}
|
||||||
cond_resched();
|
cond_resched();
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
goto send_error;
|
goto send_error;
|
||||||
}
|
}
|
||||||
/* Don't starve people filling buffers */
|
|
||||||
|
/* Don't starve people filling buffers */
|
||||||
|
if (++count >= MAX_SEND_MSG_COUNT) {
|
||||||
cond_resched();
|
cond_resched();
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock(&con->writequeue_lock);
|
spin_lock(&con->writequeue_lock);
|
||||||
e->offset += ret;
|
e->offset += ret;
|
||||||
|
@ -1430,20 +1468,19 @@ static void work_stop(void)
|
||||||
|
|
||||||
static int work_start(void)
|
static int work_start(void)
|
||||||
{
|
{
|
||||||
int error;
|
recv_workqueue = alloc_workqueue("dlm_recv", WQ_MEM_RECLAIM |
|
||||||
recv_workqueue = create_workqueue("dlm_recv");
|
WQ_HIGHPRI | WQ_FREEZEABLE, 0);
|
||||||
error = IS_ERR(recv_workqueue);
|
if (!recv_workqueue) {
|
||||||
if (error) {
|
log_print("can't start dlm_recv");
|
||||||
log_print("can't start dlm_recv %d", error);
|
return -ENOMEM;
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
send_workqueue = create_singlethread_workqueue("dlm_send");
|
send_workqueue = alloc_workqueue("dlm_send", WQ_MEM_RECLAIM |
|
||||||
error = IS_ERR(send_workqueue);
|
WQ_HIGHPRI | WQ_FREEZEABLE, 0);
|
||||||
if (error) {
|
if (!send_workqueue) {
|
||||||
log_print("can't start dlm_send %d", error);
|
log_print("can't start dlm_send");
|
||||||
destroy_workqueue(recv_workqueue);
|
destroy_workqueue(recv_workqueue);
|
||||||
return error;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue