diff options
author | tsutomu.owa@toshiba.co.jp <tsutomu.owa@toshiba.co.jp> | 2017-09-12 04:55:50 -0400 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2017-09-25 13:45:21 -0400 |
commit | b2a6662932c52304eee11323701f8a01aa110e37 (patch) | |
tree | 094b58c402c38d5fea012fefd4d029c7c0d4af90 | |
parent | f0fb83cb9201a9f272f8ac771eed6b1e5745375c (diff) |
DLM: fix race condition between dlm_send and dlm_recv
When kernel_sendpage(in send_to_sock) and kernel_recvmsg
(in receive_from_sock) return error, close_connection may works at the
same time. At that time, they may wait for each other by cancel_work_sync.
Signed-off-by: Tadashi Miyauchi <miayuchi@toshiba-tops.co.jp>
Signed-off-by: Tsutomu Owa <tsutomu.owa@toshiba.co.jp>
Signed-off-by: David Teigland <teigland@redhat.com>
-rw-r--r-- | fs/dlm/lowcomms.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 980c58befd53..420946dcb7ca 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c | |||
@@ -110,6 +110,7 @@ struct connection { | |||
110 | #define CF_IS_OTHERCON 5 | 110 | #define CF_IS_OTHERCON 5 |
111 | #define CF_CLOSE 6 | 111 | #define CF_CLOSE 6 |
112 | #define CF_APP_LIMITED 7 | 112 | #define CF_APP_LIMITED 7 |
113 | #define CF_CLOSING 8 | ||
113 | struct list_head writequeue; /* List of outgoing writequeue_entries */ | 114 | struct list_head writequeue; /* List of outgoing writequeue_entries */ |
114 | spinlock_t writequeue_lock; | 115 | spinlock_t writequeue_lock; |
115 | int (*rx_action) (struct connection *); /* What to do when active */ | 116 | int (*rx_action) (struct connection *); /* What to do when active */ |
@@ -581,9 +582,11 @@ static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port, | |||
581 | static void close_connection(struct connection *con, bool and_other, | 582 | static void close_connection(struct connection *con, bool and_other, |
582 | bool tx, bool rx) | 583 | bool tx, bool rx) |
583 | { | 584 | { |
584 | if (tx && cancel_work_sync(&con->swork)) | 585 | bool closing = test_and_set_bit(CF_CLOSING, &con->flags); |
586 | |||
587 | if (tx && !closing && cancel_work_sync(&con->swork)) | ||
585 | log_print("canceled swork for node %d", con->nodeid); | 588 | log_print("canceled swork for node %d", con->nodeid); |
586 | if (rx && cancel_work_sync(&con->rwork)) | 589 | if (rx && !closing && cancel_work_sync(&con->rwork)) |
587 | log_print("canceled rwork for node %d", con->nodeid); | 590 | log_print("canceled rwork for node %d", con->nodeid); |
588 | 591 | ||
589 | mutex_lock(&con->sock_mutex); | 592 | mutex_lock(&con->sock_mutex); |
@@ -603,6 +606,7 @@ static void close_connection(struct connection *con, bool and_other, | |||
603 | 606 | ||
604 | con->retries = 0; | 607 | con->retries = 0; |
605 | mutex_unlock(&con->sock_mutex); | 608 | mutex_unlock(&con->sock_mutex); |
609 | clear_bit(CF_CLOSING, &con->flags); | ||
606 | } | 610 | } |
607 | 611 | ||
608 | /* Data received from remote end */ | 612 | /* Data received from remote end */ |