diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-17 19:38:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-17 19:38:36 -0400 |
commit | d77bed0d4c61cb0258851367a36b358dbeb7abcc (patch) | |
tree | 36b07bcbd2bb7f29abc841281c209091ecea866f | |
parent | faeb20ecfa398b043c3224607f512c009c51653d (diff) | |
parent | b81171cb6869111dbaf9fb642f4434514c21d696 (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.c | 74 |
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 | ||
468 | static void lowcomms_error_report(struct sock *sk) | 471 | static 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); | 513 | out: |
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. */ | ||
520 | static 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 | |||
530 | static 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 */ |
506 | static void add_sock(struct socket *sock, struct connection *con) | 544 | static 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; |