Skip to content

Commit 813b0a0

Browse files
namjaejeonmehmetb0
authored andcommitted
ksmbd: add refcnt to ksmbd_conn struct
BugLink: https://bugs.launchpad.net/bugs/2089884 [ Upstream commit ee426bf ] When sending an oplock break request, opinfo->conn is used, But freed ->conn can be used on multichannel. This patch add a reference count to the ksmbd_conn struct so that it can be freed when it is no longer used. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Sasha Levin <sashal@kernel.org> [koichiroden: dropped a hunk for fs/smb/server/vfs_cache.c since c8efcc7 ("ksmbd: add support for durable handles v1/v2") is missing, adjusted context due to missing commit d1c189c ("ksmbd: use rwsem instead of rwlock for lease break")] Signed-off-by: Koichiro Den <koichiro.den@canonical.com> Signed-off-by: Roxana Nicolescu <roxana.nicolescu@canonical.com>
1 parent 413a088 commit 813b0a0

File tree

3 files changed

+20
-40
lines changed

3 files changed

+20
-40
lines changed

fs/smb/server/connection.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
3939
xa_destroy(&conn->sessions);
4040
kvfree(conn->request_buf);
4141
kfree(conn->preauth_info);
42-
kfree(conn);
42+
if (atomic_dec_and_test(&conn->refcnt))
43+
kfree(conn);
4344
}
4445

4546
/**
@@ -68,6 +69,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
6869
conn->um = NULL;
6970
atomic_set(&conn->req_running, 0);
7071
atomic_set(&conn->r_count, 0);
72+
atomic_set(&conn->refcnt, 1);
7173
conn->total_credits = 1;
7274
conn->outstanding_credits = 0;
7375

fs/smb/server/connection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ struct ksmbd_conn {
106106
bool signing_negotiated;
107107
__le16 signing_algorithm;
108108
bool binding;
109+
atomic_t refcnt;
109110
};
110111

111112
struct ksmbd_conn_ops {

fs/smb/server/oplock.c

Lines changed: 16 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
5151
init_waitqueue_head(&opinfo->oplock_brk);
5252
atomic_set(&opinfo->refcount, 1);
5353
atomic_set(&opinfo->breaking_cnt, 0);
54+
atomic_inc(&opinfo->conn->refcnt);
5455

5556
return opinfo;
5657
}
@@ -124,6 +125,8 @@ static void free_opinfo(struct oplock_info *opinfo)
124125
{
125126
if (opinfo->is_lease)
126127
free_lease(opinfo);
128+
if (opinfo->conn && atomic_dec_and_test(&opinfo->conn->refcnt))
129+
kfree(opinfo->conn);
127130
kfree(opinfo);
128131
}
129132

@@ -162,9 +165,7 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
162165
if (!atomic_inc_not_zero(&opinfo->refcount))
163166
opinfo = NULL;
164167
else {
165-
atomic_inc(&opinfo->conn->r_count);
166168
if (ksmbd_conn_releasing(opinfo->conn)) {
167-
atomic_dec(&opinfo->conn->r_count);
168169
atomic_dec(&opinfo->refcount);
169170
opinfo = NULL;
170171
}
@@ -176,26 +177,11 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
176177
return opinfo;
177178
}
178179

179-
static void opinfo_conn_put(struct oplock_info *opinfo)
180+
void opinfo_put(struct oplock_info *opinfo)
180181
{
181-
struct ksmbd_conn *conn;
182-
183182
if (!opinfo)
184183
return;
185184

186-
conn = opinfo->conn;
187-
/*
188-
* Checking waitqueue to dropping pending requests on
189-
* disconnection. waitqueue_active is safe because it
190-
* uses atomic operation for condition.
191-
*/
192-
if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
193-
wake_up(&conn->r_count_q);
194-
opinfo_put(opinfo);
195-
}
196-
197-
void opinfo_put(struct oplock_info *opinfo)
198-
{
199185
if (!atomic_dec_and_test(&opinfo->refcount))
200186
return;
201187

@@ -1130,15 +1116,12 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
11301116
if (!atomic_inc_not_zero(&opinfo->refcount))
11311117
continue;
11321118

1133-
atomic_inc(&opinfo->conn->r_count);
1134-
if (ksmbd_conn_releasing(opinfo->conn)) {
1135-
atomic_dec(&opinfo->conn->r_count);
1119+
if (ksmbd_conn_releasing(opinfo->conn))
11361120
continue;
1137-
}
11381121

11391122
read_unlock(&p_ci->m_lock);
11401123
oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
1141-
opinfo_conn_put(opinfo);
1124+
opinfo_put(opinfo);
11421125
read_lock(&p_ci->m_lock);
11431126
}
11441127
}
@@ -1172,14 +1155,11 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
11721155
if (!atomic_inc_not_zero(&opinfo->refcount))
11731156
continue;
11741157

1175-
atomic_inc(&opinfo->conn->r_count);
1176-
if (ksmbd_conn_releasing(opinfo->conn)) {
1177-
atomic_dec(&opinfo->conn->r_count);
1158+
if (ksmbd_conn_releasing(opinfo->conn))
11781159
continue;
1179-
}
11801160
read_unlock(&p_ci->m_lock);
11811161
oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
1182-
opinfo_conn_put(opinfo);
1162+
opinfo_put(opinfo);
11831163
read_lock(&p_ci->m_lock);
11841164
}
11851165
}
@@ -1259,7 +1239,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
12591239
prev_opinfo = opinfo_get_list(ci);
12601240
if (!prev_opinfo ||
12611241
(prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) {
1262-
opinfo_conn_put(prev_opinfo);
1242+
opinfo_put(prev_opinfo);
12631243
goto set_lev;
12641244
}
12651245
prev_op_has_lease = prev_opinfo->is_lease;
@@ -1269,19 +1249,19 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
12691249
if (share_ret < 0 &&
12701250
prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
12711251
err = share_ret;
1272-
opinfo_conn_put(prev_opinfo);
1252+
opinfo_put(prev_opinfo);
12731253
goto err_out;
12741254
}
12751255

12761256
if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
12771257
prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
1278-
opinfo_conn_put(prev_opinfo);
1258+
opinfo_put(prev_opinfo);
12791259
goto op_break_not_needed;
12801260
}
12811261

12821262
list_add(&work->interim_entry, &prev_opinfo->interim_list);
12831263
err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II);
1284-
opinfo_conn_put(prev_opinfo);
1264+
opinfo_put(prev_opinfo);
12851265
if (err == -ENOENT)
12861266
goto set_lev;
12871267
/* Check all oplock was freed by close */
@@ -1344,14 +1324,14 @@ static void smb_break_all_write_oplock(struct ksmbd_work *work,
13441324
return;
13451325
if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
13461326
brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
1347-
opinfo_conn_put(brk_opinfo);
1327+
opinfo_put(brk_opinfo);
13481328
return;
13491329
}
13501330

13511331
brk_opinfo->open_trunc = is_trunc;
13521332
list_add(&work->interim_entry, &brk_opinfo->interim_list);
13531333
oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II);
1354-
opinfo_conn_put(brk_opinfo);
1334+
opinfo_put(brk_opinfo);
13551335
}
13561336

13571337
/**
@@ -1380,11 +1360,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
13801360
if (!atomic_inc_not_zero(&brk_op->refcount))
13811361
continue;
13821362

1383-
atomic_inc(&brk_op->conn->r_count);
1384-
if (ksmbd_conn_releasing(brk_op->conn)) {
1385-
atomic_dec(&brk_op->conn->r_count);
1363+
if (ksmbd_conn_releasing(brk_op->conn))
13861364
continue;
1387-
}
13881365

13891366
rcu_read_unlock();
13901367
if (brk_op->is_lease && (brk_op->o_lease->state &
@@ -1415,7 +1392,7 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
14151392
brk_op->open_trunc = is_trunc;
14161393
oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE);
14171394
next:
1418-
opinfo_conn_put(brk_op);
1395+
opinfo_put(brk_op);
14191396
rcu_read_lock();
14201397
}
14211398
rcu_read_unlock();

0 commit comments

Comments
 (0)