aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dlm
diff options
context:
space:
mode:
authorBob Peterson <rpeterso@redhat.com>2017-09-12 04:55:23 -0400
committerDavid Teigland <teigland@redhat.com>2017-09-25 13:45:21 -0400
commitcc661fc934a004526a714a7b804ee3f119d27093 (patch)
tree8fc52825a065297829c027d5e45830ae258cad8e /fs/dlm
parent01da24d3fbed92dc6faf60b753e6bd50cdafb646 (diff)
DLM: Fix saving of NULL callbacks
In a previous patch I noted that accept() often copies the struct sock (sk) which overwrites the sock callbacks. However, in testing we discovered that the dlm connection structures (con) are sometimes deleted and recreated as connections come and go, and since they're zeroed out by kmem_cache_zalloc, the saved callback pointers are also initialized to zero. But with today's DLM code, the callbacks are only saved when a socket is added. During recovery testing, we discovered a common situation in which the new con is initialized to zero, then a socket is added after accept(). In this case, the sock's saved values are all NULL, but the saved values are wiped out, due to accept(). Therefore, we don't have a known good copy of the callbacks from which we can restore. Since the struct sock callbacks are always good after listen(), this patch saves the known good values after listen(). These good values are then used for subsequent restores. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Reviewed-by: Tadashi Miyauchi <miyauchi@toshiba-tops.co.jp> Signed-off-by: David Teigland <teigland@redhat.com>
Diffstat (limited to 'fs/dlm')
-rw-r--r--fs/dlm/lowcomms.c45
1 files changed, 25 insertions, 20 deletions
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index ed707d4323f4..32b534f4a9b6 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -122,10 +122,6 @@ struct connection {
122 struct connection *othercon; 122 struct connection *othercon;
123 struct work_struct rwork; /* Receive workqueue */ 123 struct work_struct rwork; /* Receive workqueue */
124 struct work_struct swork; /* Send workqueue */ 124 struct work_struct swork; /* Send workqueue */
125 void (*orig_error_report)(struct sock *);
126 void (*orig_data_ready)(struct sock *);
127 void (*orig_state_change)(struct sock *);
128 void (*orig_write_space)(struct sock *);
129}; 125};
130#define sock2con(x) ((struct connection *)(x)->sk_user_data) 126#define sock2con(x) ((struct connection *)(x)->sk_user_data)
131 127
@@ -148,6 +144,13 @@ struct dlm_node_addr {
148 struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT]; 144 struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];
149}; 145};
150 146
147static struct listen_sock_callbacks {
148 void (*sk_error_report)(struct sock *);
149 void (*sk_data_ready)(struct sock *);
150 void (*sk_state_change)(struct sock *);
151 void (*sk_write_space)(struct sock *);
152} listen_sock;
153
151static LIST_HEAD(dlm_node_addrs); 154static LIST_HEAD(dlm_node_addrs);
152static DEFINE_SPINLOCK(dlm_node_addrs_spin); 155static DEFINE_SPINLOCK(dlm_node_addrs_spin);
153 156
@@ -477,7 +480,7 @@ static void lowcomms_error_report(struct sock *sk)
477 if (con == NULL) 480 if (con == NULL)
478 goto out; 481 goto out;
479 482
480 orig_report = con->orig_error_report; 483 orig_report = listen_sock.sk_error_report;
481 if (con->sock == NULL || 484 if (con->sock == NULL ||
482 kernel_getpeername(con->sock, (struct sockaddr *)&saddr, &buflen)) { 485 kernel_getpeername(con->sock, (struct sockaddr *)&saddr, &buflen)) {
483 printk_ratelimited(KERN_ERR "dlm: node %d: socket error " 486 printk_ratelimited(KERN_ERR "dlm: node %d: socket error "
@@ -514,22 +517,26 @@ out:
514} 517}
515 518
516/* Note: sk_callback_lock must be locked before calling this function. */ 519/* Note: sk_callback_lock must be locked before calling this function. */
517static void save_callbacks(struct connection *con, struct sock *sk) 520static void save_listen_callbacks(struct socket *sock)
518{ 521{
519 con->orig_data_ready = sk->sk_data_ready; 522 struct sock *sk = sock->sk;
520 con->orig_state_change = sk->sk_state_change; 523
521 con->orig_write_space = sk->sk_write_space; 524 listen_sock.sk_data_ready = sk->sk_data_ready;
522 con->orig_error_report = sk->sk_error_report; 525 listen_sock.sk_state_change = sk->sk_state_change;
526 listen_sock.sk_write_space = sk->sk_write_space;
527 listen_sock.sk_error_report = sk->sk_error_report;
523} 528}
524 529
525static void restore_callbacks(struct connection *con, struct sock *sk) 530static void restore_callbacks(struct socket *sock)
526{ 531{
532 struct sock *sk = sock->sk;
533
527 write_lock_bh(&sk->sk_callback_lock); 534 write_lock_bh(&sk->sk_callback_lock);
528 sk->sk_user_data = NULL; 535 sk->sk_user_data = NULL;
529 sk->sk_data_ready = con->orig_data_ready; 536 sk->sk_data_ready = listen_sock.sk_data_ready;
530 sk->sk_state_change = con->orig_state_change; 537 sk->sk_state_change = listen_sock.sk_state_change;
531 sk->sk_write_space = con->orig_write_space; 538 sk->sk_write_space = listen_sock.sk_write_space;
532 sk->sk_error_report = con->orig_error_report; 539 sk->sk_error_report = listen_sock.sk_error_report;
533 write_unlock_bh(&sk->sk_callback_lock); 540 write_unlock_bh(&sk->sk_callback_lock);
534} 541}
535 542
@@ -542,8 +549,6 @@ static void add_sock(struct socket *sock, struct connection *con, bool save_cb)
542 con->sock = sock; 549 con->sock = sock;
543 550
544 sk->sk_user_data = con; 551 sk->sk_user_data = con;
545 if (save_cb)
546 save_callbacks(con, sk);
547 /* Install a data_ready callback */ 552 /* Install a data_ready callback */
548 sk->sk_data_ready = lowcomms_data_ready; 553 sk->sk_data_ready = lowcomms_data_ready;
549 sk->sk_write_space = lowcomms_write_space; 554 sk->sk_write_space = lowcomms_write_space;
@@ -583,8 +588,7 @@ static void close_connection(struct connection *con, bool and_other,
583 588
584 mutex_lock(&con->sock_mutex); 589 mutex_lock(&con->sock_mutex);
585 if (con->sock) { 590 if (con->sock) {
586 if (!test_bit(CF_IS_OTHERCON, &con->flags)) 591 restore_callbacks(con->sock);
587 restore_callbacks(con, con->sock->sk);
588 sock_release(con->sock); 592 sock_release(con->sock);
589 con->sock = NULL; 593 con->sock = NULL;
590 } 594 }
@@ -1226,7 +1230,7 @@ static struct socket *tcp_create_listen_sock(struct connection *con,
1226 log_print("Failed to set SO_REUSEADDR on socket: %d", result); 1230 log_print("Failed to set SO_REUSEADDR on socket: %d", result);
1227 } 1231 }
1228 sock->sk->sk_user_data = con; 1232 sock->sk->sk_user_data = con;
1229 1233 save_listen_callbacks(sock);
1230 con->rx_action = tcp_accept_from_sock; 1234 con->rx_action = tcp_accept_from_sock;
1231 con->connect_action = tcp_connect_to_sock; 1235 con->connect_action = tcp_connect_to_sock;
1232 1236
@@ -1310,6 +1314,7 @@ static int sctp_listen_for_all(void)
1310 write_lock_bh(&sock->sk->sk_callback_lock); 1314 write_lock_bh(&sock->sk->sk_callback_lock);
1311 /* Init con struct */ 1315 /* Init con struct */
1312 sock->sk->sk_user_data = con; 1316 sock->sk->sk_user_data = con;
1317 save_listen_callbacks(sock);
1313 con->sock = sock; 1318 con->sock = sock;
1314 con->sock->sk->sk_data_ready = lowcomms_data_ready; 1319 con->sock->sk->sk_data_ready = lowcomms_data_ready;
1315 con->rx_action = sctp_accept_from_sock; 1320 con->rx_action = sctp_accept_from_sock;