aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Peterson <rpeterso@redhat.com>2016-02-05 14:39:02 -0500
committerDavid Teigland <teigland@redhat.com>2016-02-22 15:02:17 -0500
commitb81171cb6869111dbaf9fb642f4434514c21d696 (patch)
treeee4a60628eae1e09006f50df50076b519f82306b
parent1a31833d085a339cf42573de0717209e8b2172e8 (diff)
DLM: Save and restore socket callbacks properly
This patch fixes the problems with patch b3a5bbfd7. 1. It removes a return statement from lowcomms_error_report because it needs to call the original error report in all paths through the function. 2. All socket callbacks are saved and restored, not just the sk_error_report, and that's done so with proper locking like sunrpc does. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: David Teigland <teigland@redhat.com>
-rw-r--r--fs/dlm/lowcomms.c70
1 files changed, 59 insertions, 11 deletions
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index dc9ae6d670dc..00640e70ed7a 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -124,7 +124,10 @@ struct connection {
124 struct connection *othercon; 124 struct connection *othercon;
125 struct work_struct rwork; /* Receive workqueue */ 125 struct work_struct rwork; /* Receive workqueue */
126 struct work_struct swork; /* Send workqueue */ 126 struct work_struct swork; /* Send workqueue */
127 void (*orig_error_report)(struct sock *sk); 127 void (*orig_error_report)(struct sock *);
128 void (*orig_data_ready)(struct sock *);
129 void (*orig_state_change)(struct sock *);
130 void (*orig_write_space)(struct sock *);
128}; 131};
129#define sock2con(x) ((struct connection *)(x)->sk_user_data) 132#define sock2con(x) ((struct connection *)(x)->sk_user_data)
130 133
@@ -467,10 +470,17 @@ int dlm_lowcomms_connect_node(int nodeid)
467 470
468static void lowcomms_error_report(struct sock *sk) 471static void lowcomms_error_report(struct sock *sk)
469{ 472{
470 struct connection *con = sock2con(sk); 473 struct connection *con;
471 struct sockaddr_storage saddr; 474 struct sockaddr_storage saddr;
472 int buflen; 475 int buflen;
476 void (*orig_report)(struct sock *) = NULL;
473 477
478 read_lock_bh(&sk->sk_callback_lock);
479 con = sock2con(sk);
480 if (con == NULL)
481 goto out;
482
483 orig_report = con->orig_error_report;
474 if (con->sock == NULL || 484 if (con->sock == NULL ||
475 kernel_getpeername(con->sock, (struct sockaddr *)&saddr, &buflen)) { 485 kernel_getpeername(con->sock, (struct sockaddr *)&saddr, &buflen)) {
476 printk_ratelimited(KERN_ERR "dlm: node %d: socket error " 486 printk_ratelimited(KERN_ERR "dlm: node %d: socket error "
@@ -478,7 +488,6 @@ static void lowcomms_error_report(struct sock *sk)
478 "sk_err=%d/%d\n", dlm_our_nodeid(), 488 "sk_err=%d/%d\n", dlm_our_nodeid(),
479 con->nodeid, dlm_config.ci_tcp_port, 489 con->nodeid, dlm_config.ci_tcp_port,
480 sk->sk_err, sk->sk_err_soft); 490 sk->sk_err, sk->sk_err_soft);
481 return;
482 } else if (saddr.ss_family == AF_INET) { 491 } else if (saddr.ss_family == AF_INET) {
483 struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr; 492 struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr;
484 493
@@ -501,22 +510,54 @@ static void lowcomms_error_report(struct sock *sk)
501 dlm_config.ci_tcp_port, sk->sk_err, 510 dlm_config.ci_tcp_port, sk->sk_err,
502 sk->sk_err_soft); 511 sk->sk_err_soft);
503 } 512 }
504 con->orig_error_report(sk); 513out:
514 read_unlock_bh(&sk->sk_callback_lock);
515 if (orig_report)
516 orig_report(sk);
517}
518
519/* Note: sk_callback_lock must be locked before calling this function. */
520static void save_callbacks(struct connection *con, struct sock *sk)
521{
522 lock_sock(sk);
523 con->orig_data_ready = sk->sk_data_ready;
524 con->orig_state_change = sk->sk_state_change;
525 con->orig_write_space = sk->sk_write_space;
526 con->orig_error_report = sk->sk_error_report;
527 release_sock(sk);
528}
529
530static void restore_callbacks(struct connection *con, struct sock *sk)
531{
532 write_lock_bh(&sk->sk_callback_lock);
533 lock_sock(sk);
534 sk->sk_user_data = NULL;
535 sk->sk_data_ready = con->orig_data_ready;
536 sk->sk_state_change = con->orig_state_change;
537 sk->sk_write_space = con->orig_write_space;
538 sk->sk_error_report = con->orig_error_report;
539 release_sock(sk);
540 write_unlock_bh(&sk->sk_callback_lock);
505} 541}
506 542
507/* Make a socket active */ 543/* Make a socket active */
508static void add_sock(struct socket *sock, struct connection *con) 544static void add_sock(struct socket *sock, struct connection *con)
509{ 545{
546 struct sock *sk = sock->sk;
547
548 write_lock_bh(&sk->sk_callback_lock);
510 con->sock = sock; 549 con->sock = sock;
511 550
551 sk->sk_user_data = con;
552 if (!test_bit(CF_IS_OTHERCON, &con->flags))
553 save_callbacks(con, sk);
512 /* Install a data_ready callback */ 554 /* Install a data_ready callback */
513 con->sock->sk->sk_data_ready = lowcomms_data_ready; 555 sk->sk_data_ready = lowcomms_data_ready;
514 con->sock->sk->sk_write_space = lowcomms_write_space; 556 sk->sk_write_space = lowcomms_write_space;
515 con->sock->sk->sk_state_change = lowcomms_state_change; 557 sk->sk_state_change = lowcomms_state_change;
516 con->sock->sk->sk_user_data = con; 558 sk->sk_allocation = GFP_NOFS;
517 con->sock->sk->sk_allocation = GFP_NOFS; 559 sk->sk_error_report = lowcomms_error_report;
518 con->orig_error_report = con->sock->sk->sk_error_report; 560 write_unlock_bh(&sk->sk_callback_lock);
519 con->sock->sk->sk_error_report = lowcomms_error_report;
520} 561}
521 562
522/* Add the port number to an IPv6 or 4 sockaddr and return the address 563/* Add the port number to an IPv6 or 4 sockaddr and return the address
@@ -551,6 +592,8 @@ static void close_connection(struct connection *con, bool and_other,
551 592
552 mutex_lock(&con->sock_mutex); 593 mutex_lock(&con->sock_mutex);
553 if (con->sock) { 594 if (con->sock) {
595 if (!test_bit(CF_IS_OTHERCON, &con->flags))
596 restore_callbacks(con, con->sock->sk);
554 sock_release(con->sock); 597 sock_release(con->sock);
555 con->sock = NULL; 598 con->sock = NULL;
556 } 599 }
@@ -1192,6 +1235,8 @@ static struct socket *tcp_create_listen_sock(struct connection *con,
1192 if (result < 0) { 1235 if (result < 0) {
1193 log_print("Failed to set SO_REUSEADDR on socket: %d", result); 1236 log_print("Failed to set SO_REUSEADDR on socket: %d", result);
1194 } 1237 }
1238 sock->sk->sk_user_data = con;
1239
1195 con->rx_action = tcp_accept_from_sock; 1240 con->rx_action = tcp_accept_from_sock;
1196 con->connect_action = tcp_connect_to_sock; 1241 con->connect_action = tcp_connect_to_sock;
1197 1242
@@ -1273,6 +1318,7 @@ static int sctp_listen_for_all(void)
1273 if (result < 0) 1318 if (result < 0)
1274 log_print("Could not set SCTP NODELAY error %d\n", result); 1319 log_print("Could not set SCTP NODELAY error %d\n", result);
1275 1320
1321 write_lock_bh(&sock->sk->sk_callback_lock);
1276 /* Init con struct */ 1322 /* Init con struct */
1277 sock->sk->sk_user_data = con; 1323 sock->sk->sk_user_data = con;
1278 con->sock = sock; 1324 con->sock = sock;
@@ -1280,6 +1326,8 @@ static int sctp_listen_for_all(void)
1280 con->rx_action = sctp_accept_from_sock; 1326 con->rx_action = sctp_accept_from_sock;
1281 con->connect_action = sctp_connect_to_sock; 1327 con->connect_action = sctp_connect_to_sock;
1282 1328
1329 write_unlock_bh(&sock->sk->sk_callback_lock);
1330
1283 /* Bind to all addresses. */ 1331 /* Bind to all addresses. */
1284 if (sctp_bind_addrs(con, dlm_config.ci_tcp_port)) 1332 if (sctp_bind_addrs(con, dlm_config.ci_tcp_port))
1285 goto create_delsock; 1333 goto create_delsock;