aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-03-17 19:38:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-17 19:38:36 -0400
commitd77bed0d4c61cb0258851367a36b358dbeb7abcc (patch)
tree36b07bcbd2bb7f29abc841281c209091ecea866f
parentfaeb20ecfa398b043c3224607f512c009c51653d (diff)
parentb81171cb6869111dbaf9fb642f4434514c21d696 (diff)
Merge tag 'dlm-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm
Pull dlm updates from David Teigland: "Previous changes introduced the use of socket error reporting for dlm sockets. This set includes two fixes in how the socket error callbacks are used" * tag 'dlm-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm: DLM: Save and restore socket callbacks properly DLM: Replace nodeid_to_addr with kernel_getpeername
-rw-r--r--fs/dlm/lowcomms.c74
1 files changed, 62 insertions, 12 deletions
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 3a37bd3f9637..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,16 +470,24 @@ 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;
475 int buflen;
476 void (*orig_report)(struct sock *) = NULL;
472 477
473 if (nodeid_to_addr(con->nodeid, &saddr, NULL, false)) { 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;
484 if (con->sock == NULL ||
485 kernel_getpeername(con->sock, (struct sockaddr *)&saddr, &buflen)) {
474 printk_ratelimited(KERN_ERR "dlm: node %d: socket error " 486 printk_ratelimited(KERN_ERR "dlm: node %d: socket error "
475 "sending to node %d, port %d, " 487 "sending to node %d, port %d, "
476 "sk_err=%d/%d\n", dlm_our_nodeid(), 488 "sk_err=%d/%d\n", dlm_our_nodeid(),
477 con->nodeid, dlm_config.ci_tcp_port, 489 con->nodeid, dlm_config.ci_tcp_port,
478 sk->sk_err, sk->sk_err_soft); 490 sk->sk_err, sk->sk_err_soft);
479 return;
480 } else if (saddr.ss_family == AF_INET) { 491 } else if (saddr.ss_family == AF_INET) {
481 struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr; 492 struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr;
482 493
@@ -499,22 +510,54 @@ static void lowcomms_error_report(struct sock *sk)
499 dlm_config.ci_tcp_port, sk->sk_err, 510 dlm_config.ci_tcp_port, sk->sk_err,
500 sk->sk_err_soft); 511 sk->sk_err_soft);
501 } 512 }
502 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);
503} 541}
504 542
505/* Make a socket active */ 543/* Make a socket active */
506static void add_sock(struct socket *sock, struct connection *con) 544static void add_sock(struct socket *sock, struct connection *con)
507{ 545{
546 struct sock *sk = sock->sk;
547
548 write_lock_bh(&sk->sk_callback_lock);
508 con->sock = sock; 549 con->sock = sock;
509 550
551 sk->sk_user_data = con;
552 if (!test_bit(CF_IS_OTHERCON, &con->flags))
553 save_callbacks(con, sk);
510 /* Install a data_ready callback */ 554 /* Install a data_ready callback */
511 con->sock->sk->sk_data_ready = lowcomms_data_ready; 555 sk->sk_data_ready = lowcomms_data_ready;
512 con->sock->sk->sk_write_space = lowcomms_write_space; 556 sk->sk_write_space = lowcomms_write_space;
513 con->sock->sk->sk_state_change = lowcomms_state_change; 557 sk->sk_state_change = lowcomms_state_change;
514 con->sock->sk->sk_user_data = con; 558 sk->sk_allocation = GFP_NOFS;
515 con->sock->sk->sk_allocation = GFP_NOFS; 559 sk->sk_error_report = lowcomms_error_report;
516 con->orig_error_report = con->sock->sk->sk_error_report; 560 write_unlock_bh(&sk->sk_callback_lock);
517 con->sock->sk->sk_error_report = lowcomms_error_report;
518} 561}
519 562
520/* 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
@@ -549,6 +592,8 @@ static void close_connection(struct connection *con, bool and_other,
549 592
550 mutex_lock(&con->sock_mutex); 593 mutex_lock(&con->sock_mutex);
551 if (con->sock) { 594 if (con->sock) {
595 if (!test_bit(CF_IS_OTHERCON, &con->flags))
596 restore_callbacks(con, con->sock->sk);
552 sock_release(con->sock); 597 sock_release(con->sock);
553 con->sock = NULL; 598 con->sock = NULL;
554 } 599 }
@@ -1190,6 +1235,8 @@ static struct socket *tcp_create_listen_sock(struct connection *con,
1190 if (result < 0) { 1235 if (result < 0) {
1191 log_print("Failed to set SO_REUSEADDR on socket: %d", result); 1236 log_print("Failed to set SO_REUSEADDR on socket: %d", result);
1192 } 1237 }
1238 sock->sk->sk_user_data = con;
1239
1193 con->rx_action = tcp_accept_from_sock; 1240 con->rx_action = tcp_accept_from_sock;
1194 con->connect_action = tcp_connect_to_sock; 1241 con->connect_action = tcp_connect_to_sock;
1195 1242
@@ -1271,6 +1318,7 @@ static int sctp_listen_for_all(void)
1271 if (result < 0) 1318 if (result < 0)
1272 log_print("Could not set SCTP NODELAY error %d\n", result); 1319 log_print("Could not set SCTP NODELAY error %d\n", result);
1273 1320
1321 write_lock_bh(&sock->sk->sk_callback_lock);
1274 /* Init con struct */ 1322 /* Init con struct */
1275 sock->sk->sk_user_data = con; 1323 sock->sk->sk_user_data = con;
1276 con->sock = sock; 1324 con->sock = sock;
@@ -1278,6 +1326,8 @@ static int sctp_listen_for_all(void)
1278 con->rx_action = sctp_accept_from_sock; 1326 con->rx_action = sctp_accept_from_sock;
1279 con->connect_action = sctp_connect_to_sock; 1327 con->connect_action = sctp_connect_to_sock;
1280 1328
1329 write_unlock_bh(&sock->sk->sk_callback_lock);
1330
1281 /* Bind to all addresses. */ 1331 /* Bind to all addresses. */
1282 if (sctp_bind_addrs(con, dlm_config.ci_tcp_port)) 1332 if (sctp_bind_addrs(con, dlm_config.ci_tcp_port))
1283 goto create_delsock; 1333 goto create_delsock;