From 97a934a6158ee08f71369767f68323ccadf33654 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 3 Oct 2023 22:29:26 +0900 Subject: [PATCH] ksmbd: update tree disconnect race update 2 Signed-off-by: Namjae Jeon --- mgmt/tree_connect.c | 18 +++++++++++------- smb2pdu.c | 15 +++++++++++++-- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/mgmt/tree_connect.c b/mgmt/tree_connect.c index 9f7b80b37..3951cf0d2 100644 --- a/mgmt/tree_connect.c +++ b/mgmt/tree_connect.c @@ -109,12 +109,6 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, int ret; write_lock(&sess->tree_conns_lock); - if (tree_conn->t_state == TREE_DISCONNECTED) { - write_unlock(&sess->tree_conns_lock); - return -ENOENT; - } - - tree_conn->t_state = TREE_DISCONNECTED; xa_erase(&sess->tree_conns, tree_conn->id); write_unlock(&sess->tree_conns_lock); @@ -156,8 +150,18 @@ int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess) if (!sess) return -EINVAL; - xa_for_each(&sess->tree_conns, id, tc) + xa_for_each(&sess->tree_conns, id, tc) { + write_lock(&sess->tree_conns_lock); + if (tc->t_state == TREE_DISCONNECTED) { + write_unlock(&sess->tree_conns_lock); + ret = -ENOENT; + continue; + } + tc->t_state = TREE_DISCONNECTED; + write_unlock(&sess->tree_conns_lock); + ret |= ksmbd_tree_conn_disconnect(sess, tc); + } xa_destroy(&sess->tree_conns); return ret; } diff --git a/smb2pdu.c b/smb2pdu.c index 8e28285b7..afbd650eb 100644 --- a/smb2pdu.c +++ b/smb2pdu.c @@ -2146,13 +2146,24 @@ int smb2_tree_disconnect(struct ksmbd_work *work) ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; - smb2_set_err_rsp(work); err = -ENOENT; goto err_out; } ksmbd_close_tree_conn_fds(work); - atomic_dec(&tcon->refcount); + + write_lock(&sess->tree_conns_lock); + if (tcon->t_state == TREE_DISCONNECTED) { + write_unlock(&sess->tree_conns_lock); + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; + err = -ENOENT; + goto err_out; + } + + BUG_ON(atomic_dec_and_test(&tcon->refcount)); + tcon->t_state = TREE_DISCONNECTED; + write_unlock(&sess->tree_conns_lock); + err = ksmbd_tree_conn_disconnect(sess, tcon); if (err) { rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;