| From 9b046013e5837f8a58453d1e9f8e01d03adb7fe7 Mon Sep 17 00:00:00 2001 |
| From: Dmitry Eremin <dmitry.eremin@intel.com> |
| Date: Thu, 25 Jan 2018 16:51:04 +0300 |
| Subject: staging: lustre: separate a connection destroy from free struct kib_conn |
| |
| From: Dmitry Eremin <dmitry.eremin@intel.com> |
| |
| commit 9b046013e5837f8a58453d1e9f8e01d03adb7fe7 upstream. |
| |
| The logic of the original commit 4d99b2581eff ("staging: lustre: avoid |
| intensive reconnecting for ko2iblnd") was assumed conditional free of |
| struct kib_conn if the second argument free_conn in function |
| kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn) is true. |
| But this hunk of code was dropped from original commit. As result the logic |
| works wrong and current code use struct kib_conn after free. |
| |
| > drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c |
| > 3317 kiblnd_destroy_conn(conn, !peer); |
| > ^^^^ Freed always (but should be conditionally) |
| > 3318 |
| > 3319 spin_lock_irqsave(lock, flags); |
| > 3320 if (!peer) |
| > 3321 continue; |
| > 3322 |
| > 3323 conn->ibc_peer = peer; |
| > ^^^^^^^^^^^^^^ Use after free |
| > 3324 if (peer->ibp_reconnected < KIB_RECONN_HIGH_RACE) |
| > 3325 list_add_tail(&conn->ibc_list, |
| > ^^^^^^^^^^^^^^ Use after free |
| > 3326 &kiblnd_data.kib_reconn_list); |
| > 3327 else |
| > 3328 list_add_tail(&conn->ibc_list, |
| > ^^^^^^^^^^^^^^ Use after free |
| > 3329 &kiblnd_data.kib_reconn_wait); |
| |
| To avoid confusion this fix moved the freeing a struct kib_conn outside of |
| the function kiblnd_destroy_conn() and free as it was intended in original |
| commit. |
| |
| Fixes: 4d99b2581eff ("staging: lustre: avoid intensive reconnecting for ko2iblnd") |
| Signed-off-by: Dmitry Eremin <Dmitry.Eremin@intel.com> |
| Reviewed-by: Andreas Dilger <andreas.dilger@intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 7 +++---- |
| drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 2 +- |
| drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 6 ++++-- |
| 3 files changed, 8 insertions(+), 7 deletions(-) |
| |
| --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c |
| +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c |
| @@ -824,14 +824,15 @@ struct kib_conn *kiblnd_create_conn(stru |
| return conn; |
| |
| failed_2: |
| - kiblnd_destroy_conn(conn, true); |
| + kiblnd_destroy_conn(conn); |
| + LIBCFS_FREE(conn, sizeof(*conn)); |
| failed_1: |
| LIBCFS_FREE(init_qp_attr, sizeof(*init_qp_attr)); |
| failed_0: |
| return NULL; |
| } |
| |
| -void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn) |
| +void kiblnd_destroy_conn(struct kib_conn *conn) |
| { |
| struct rdma_cm_id *cmid = conn->ibc_cmid; |
| struct kib_peer *peer = conn->ibc_peer; |
| @@ -894,8 +895,6 @@ void kiblnd_destroy_conn(struct kib_conn |
| rdma_destroy_id(cmid); |
| atomic_dec(&net->ibn_nconns); |
| } |
| - |
| - LIBCFS_FREE(conn, sizeof(*conn)); |
| } |
| |
| int kiblnd_close_peer_conns_locked(struct kib_peer *peer, int why) |
| --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h |
| +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h |
| @@ -1018,7 +1018,7 @@ int kiblnd_close_peer_conns_locked(stru |
| struct kib_conn *kiblnd_create_conn(struct kib_peer *peer, |
| struct rdma_cm_id *cmid, |
| int state, int version); |
| -void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn); |
| +void kiblnd_destroy_conn(struct kib_conn *conn); |
| void kiblnd_close_conn(struct kib_conn *conn, int error); |
| void kiblnd_close_conn_locked(struct kib_conn *conn, int error); |
| |
| --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c |
| +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c |
| @@ -3323,11 +3323,13 @@ kiblnd_connd(void *arg) |
| spin_unlock_irqrestore(lock, flags); |
| dropped_lock = 1; |
| |
| - kiblnd_destroy_conn(conn, !peer); |
| + kiblnd_destroy_conn(conn); |
| |
| spin_lock_irqsave(lock, flags); |
| - if (!peer) |
| + if (!peer) { |
| + kfree(conn); |
| continue; |
| + } |
| |
| conn->ibc_peer = peer; |
| if (peer->ibp_reconnected < KIB_RECONN_HIGH_RACE) |