Skip to content

Commit 9dad867

Browse files
committed
ksmbd: prevent connection free while sending oplock break notification
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
1 parent fe575dd commit 9dad867

File tree

4 files changed

+32
-14
lines changed

4 files changed

+32
-14
lines changed

connection.c

+20
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,26 @@ void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops)
485485
default_conn_ops.terminate_fn = ops->terminate_fn;
486486
}
487487

488+
void ksmbd_conn_r_count_inc(struct ksmbd_conn *conn)
489+
{
490+
atomic_inc(&conn->r_count);
491+
}
492+
493+
void ksmbd_conn_r_count_dec(struct ksmbd_conn *conn)
494+
{
495+
/*
496+
* Checking waitqueue to dropping pending requests on
497+
* disconnection. waitqueue_active is safe because it
498+
* uses atomic operation for condition.
499+
*/
500+
atomic_inc(&conn->refcnt);
501+
if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
502+
wake_up(&conn->r_count_q);
503+
504+
if (atomic_dec_and_test(&conn->refcnt))
505+
kfree(conn);
506+
}
507+
488508
int ksmbd_conn_transport_init(void)
489509
{
490510
int ret;

connection.h

+2
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ int ksmbd_conn_transport_init(void);
168168
void ksmbd_conn_transport_destroy(void);
169169
void ksmbd_conn_lock(struct ksmbd_conn *conn);
170170
void ksmbd_conn_unlock(struct ksmbd_conn *conn);
171+
void ksmbd_conn_r_count_inc(struct ksmbd_conn *conn);
172+
void ksmbd_conn_r_count_dec(struct ksmbd_conn *conn);
171173

172174
/*
173175
* WARNING

oplock.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -740,8 +740,7 @@ static void __smb1_oplock_break_noti(struct work_struct *wk)
740740

741741
if (allocate_interim_rsp_buf(work)) {
742742
pr_err("smb_allocate_rsp_buf failed! ");
743-
ksmbd_free_work_struct(work);
744-
return;
743+
goto out;
745744
}
746745

747746
/* Init response header */
@@ -786,7 +785,9 @@ static void __smb1_oplock_break_noti(struct work_struct *wk)
786785
req->Fid, req->OplockLevel);
787786

788787
ksmbd_conn_write(work);
788+
out:
789789
ksmbd_free_work_struct(work);
790+
ksmbd_conn_r_count_dec(work->conn);
790791
}
791792

792793
/**
@@ -809,6 +810,7 @@ static int smb1_oplock_break_noti(struct oplock_info *opinfo)
809810
work->conn = conn;
810811

811812
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
813+
ksmbd_conn_r_count_inc(conn);
812814
INIT_WORK(&work->work, __smb1_oplock_break_noti);
813815
ksmbd_queue_work(work);
814816

@@ -891,6 +893,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
891893

892894
out:
893895
ksmbd_free_work_struct(work);
896+
ksmbd_conn_r_count_dec(work->conn);
894897
}
895898

896899
/**
@@ -925,6 +928,7 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
925928
work->sess = opinfo->sess;
926929

927930
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
931+
ksmbd_conn_r_count_inc(conn);
928932
INIT_WORK(&work->work, __smb2_oplock_break_noti);
929933
ksmbd_queue_work(work);
930934

@@ -992,6 +996,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
992996

993997
out:
994998
ksmbd_free_work_struct(work);
999+
ksmbd_conn_r_count_dec(work->conn);
9951000
}
9961001

9971002
/**
@@ -1031,6 +1036,7 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
10311036
work->sess = opinfo->sess;
10321037

10331038
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
1039+
ksmbd_conn_r_count_inc(conn);
10341040
INIT_WORK(&work->work, __smb2_lease_break_noti);
10351041
ksmbd_queue_work(work);
10361042
wait_for_break_ack(opinfo);

server.c

+2-12
Original file line numberDiff line numberDiff line change
@@ -270,17 +270,7 @@ static void handle_ksmbd_work(struct work_struct *wk)
270270

271271
ksmbd_conn_try_dequeue_request(work);
272272
ksmbd_free_work_struct(work);
273-
/*
274-
* Checking waitqueue to dropping pending requests on
275-
* disconnection. waitqueue_active is safe because it
276-
* uses atomic operation for condition.
277-
*/
278-
atomic_inc(&conn->refcnt);
279-
if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
280-
wake_up(&conn->r_count_q);
281-
282-
if (atomic_dec_and_test(&conn->refcnt))
283-
kfree(conn);
273+
ksmbd_conn_r_count_dec(conn);
284274
}
285275

286276
/**
@@ -310,7 +300,7 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
310300
conn->request_buf = NULL;
311301

312302
ksmbd_conn_enqueue_request(work);
313-
atomic_inc(&conn->r_count);
303+
ksmbd_conn_r_count_inc(conn);
314304
/* update activity on connection */
315305
conn->last_active = jiffies;
316306
INIT_WORK(&work->work, handle_ksmbd_work);

0 commit comments

Comments
 (0)