Skip to content

Commit 97b9af7

Browse files
Wen Gukuba-moo
authored andcommitted
net/smc: Only save the original clcsock callback functions
Both listen and fallback process will save the current clcsock callback functions and establish new ones. But if both of them happen, the saved callback functions will be overwritten. So this patch introduces some helpers to ensure that only save the original callback functions of clcsock. Fixes: 341adee ("net/smc: Forward wakeup to smc socket waitqueue after fallback") Signed-off-by: Wen Gu <[email protected]> Acked-by: Karsten Graul <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent ba5a4fd commit 97b9af7

File tree

3 files changed

+67
-20
lines changed

3 files changed

+67
-20
lines changed

net/smc/af_smc.c

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
373373
sk->sk_prot->hash(sk);
374374
sk_refcnt_debug_inc(sk);
375375
mutex_init(&smc->clcsock_release_lock);
376+
smc_init_saved_callbacks(smc);
376377

377378
return sk;
378379
}
@@ -782,20 +783,32 @@ static void smc_fback_error_report(struct sock *clcsk)
782783
smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_error_report);
783784
}
784785

786+
static void smc_fback_replace_callbacks(struct smc_sock *smc)
787+
{
788+
struct sock *clcsk = smc->clcsock->sk;
789+
790+
clcsk->sk_user_data = (void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
791+
792+
smc_clcsock_replace_cb(&clcsk->sk_state_change, smc_fback_state_change,
793+
&smc->clcsk_state_change);
794+
smc_clcsock_replace_cb(&clcsk->sk_data_ready, smc_fback_data_ready,
795+
&smc->clcsk_data_ready);
796+
smc_clcsock_replace_cb(&clcsk->sk_write_space, smc_fback_write_space,
797+
&smc->clcsk_write_space);
798+
smc_clcsock_replace_cb(&clcsk->sk_error_report, smc_fback_error_report,
799+
&smc->clcsk_error_report);
800+
}
801+
785802
static int smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
786803
{
787-
struct sock *clcsk;
788804
int rc = 0;
789805

790806
mutex_lock(&smc->clcsock_release_lock);
791807
if (!smc->clcsock) {
792808
rc = -EBADF;
793809
goto out;
794810
}
795-
clcsk = smc->clcsock->sk;
796811

797-
if (smc->use_fallback)
798-
goto out;
799812
smc->use_fallback = true;
800813
smc->fallback_rsn = reason_code;
801814
smc_stat_fallback(smc);
@@ -810,18 +823,7 @@ static int smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
810823
* in smc sk->sk_wq and they should be woken up
811824
* as clcsock's wait queue is woken up.
812825
*/
813-
smc->clcsk_state_change = clcsk->sk_state_change;
814-
smc->clcsk_data_ready = clcsk->sk_data_ready;
815-
smc->clcsk_write_space = clcsk->sk_write_space;
816-
smc->clcsk_error_report = clcsk->sk_error_report;
817-
818-
clcsk->sk_state_change = smc_fback_state_change;
819-
clcsk->sk_data_ready = smc_fback_data_ready;
820-
clcsk->sk_write_space = smc_fback_write_space;
821-
clcsk->sk_error_report = smc_fback_error_report;
822-
823-
smc->clcsock->sk->sk_user_data =
824-
(void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
826+
smc_fback_replace_callbacks(smc);
825827
}
826828
out:
827829
mutex_unlock(&smc->clcsock_release_lock);
@@ -1596,6 +1598,19 @@ static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc)
15961598
* function; switch it back to the original sk_data_ready function
15971599
*/
15981600
new_clcsock->sk->sk_data_ready = lsmc->clcsk_data_ready;
1601+
1602+
/* if new clcsock has also inherited the fallback-specific callback
1603+
* functions, switch them back to the original ones.
1604+
*/
1605+
if (lsmc->use_fallback) {
1606+
if (lsmc->clcsk_state_change)
1607+
new_clcsock->sk->sk_state_change = lsmc->clcsk_state_change;
1608+
if (lsmc->clcsk_write_space)
1609+
new_clcsock->sk->sk_write_space = lsmc->clcsk_write_space;
1610+
if (lsmc->clcsk_error_report)
1611+
new_clcsock->sk->sk_error_report = lsmc->clcsk_error_report;
1612+
}
1613+
15991614
(*new_smc)->clcsock = new_clcsock;
16001615
out:
16011616
return rc;
@@ -2397,10 +2412,10 @@ static int smc_listen(struct socket *sock, int backlog)
23972412
/* save original sk_data_ready function and establish
23982413
* smc-specific sk_data_ready function
23992414
*/
2400-
smc->clcsk_data_ready = smc->clcsock->sk->sk_data_ready;
2401-
smc->clcsock->sk->sk_data_ready = smc_clcsock_data_ready;
24022415
smc->clcsock->sk->sk_user_data =
24032416
(void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
2417+
smc_clcsock_replace_cb(&smc->clcsock->sk->sk_data_ready,
2418+
smc_clcsock_data_ready, &smc->clcsk_data_ready);
24042419

24052420
/* save original ops */
24062421
smc->ori_af_ops = inet_csk(smc->clcsock->sk)->icsk_af_ops;
@@ -2415,7 +2430,9 @@ static int smc_listen(struct socket *sock, int backlog)
24152430

24162431
rc = kernel_listen(smc->clcsock, backlog);
24172432
if (rc) {
2418-
smc->clcsock->sk->sk_data_ready = smc->clcsk_data_ready;
2433+
smc_clcsock_restore_cb(&smc->clcsock->sk->sk_data_ready,
2434+
&smc->clcsk_data_ready);
2435+
smc->clcsock->sk->sk_user_data = NULL;
24192436
goto out;
24202437
}
24212438
sk->sk_max_ack_backlog = backlog;

net/smc/smc.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,12 +288,41 @@ static inline struct smc_sock *smc_sk(const struct sock *sk)
288288
return (struct smc_sock *)sk;
289289
}
290290

291+
static inline void smc_init_saved_callbacks(struct smc_sock *smc)
292+
{
293+
smc->clcsk_state_change = NULL;
294+
smc->clcsk_data_ready = NULL;
295+
smc->clcsk_write_space = NULL;
296+
smc->clcsk_error_report = NULL;
297+
}
298+
291299
static inline struct smc_sock *smc_clcsock_user_data(const struct sock *clcsk)
292300
{
293301
return (struct smc_sock *)
294302
((uintptr_t)clcsk->sk_user_data & ~SK_USER_DATA_NOCOPY);
295303
}
296304

305+
/* save target_cb in saved_cb, and replace target_cb with new_cb */
306+
static inline void smc_clcsock_replace_cb(void (**target_cb)(struct sock *),
307+
void (*new_cb)(struct sock *),
308+
void (**saved_cb)(struct sock *))
309+
{
310+
/* only save once */
311+
if (!*saved_cb)
312+
*saved_cb = *target_cb;
313+
*target_cb = new_cb;
314+
}
315+
316+
/* restore target_cb to saved_cb, and reset saved_cb to NULL */
317+
static inline void smc_clcsock_restore_cb(void (**target_cb)(struct sock *),
318+
void (**saved_cb)(struct sock *))
319+
{
320+
if (!*saved_cb)
321+
return;
322+
*target_cb = *saved_cb;
323+
*saved_cb = NULL;
324+
}
325+
297326
extern struct workqueue_struct *smc_hs_wq; /* wq for handshake work */
298327
extern struct workqueue_struct *smc_close_wq; /* wq for close work */
299328

net/smc/smc_close.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,8 @@ int smc_close_active(struct smc_sock *smc)
214214
sk->sk_state = SMC_CLOSED;
215215
sk->sk_state_change(sk); /* wake up accept */
216216
if (smc->clcsock && smc->clcsock->sk) {
217-
smc->clcsock->sk->sk_data_ready = smc->clcsk_data_ready;
217+
smc_clcsock_restore_cb(&smc->clcsock->sk->sk_data_ready,
218+
&smc->clcsk_data_ready);
218219
smc->clcsock->sk->sk_user_data = NULL;
219220
rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR);
220221
}

0 commit comments

Comments
 (0)