three kernel server fixes

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmdi9NcACgkQiiy9cAdy
 T1EBZwv+JAGDnHiDVm4FuYg4Q0jNHjmSoJ4HkiSNSB/hKtdmA9q6xHJ76Nfrbzig
 1EczCe9vAf5i9yYs4acPTT0MOK9lCyarFCYY02Dk3+/JPuyFLC5VkjplvryMGeXm
 9Py07XSIFcx3EZ1Ws597OMVvTtdTzRp8EXGt6xoMmqgQhma7ggSgvXCmoC4nCf/S
 I2CMGx3ieeF5aPiosf8YEAjn4+MZJr4CI5hut5XZYgxND27QiB5gdPMSiHReANyi
 hBF8u2mwyayztlEkknmU/7TMSwJiO3zsCMLU/wECJaZgDBb5LcuWS0f9BmI8eCgj
 6gk+aX6aQ6Xnx0rNdl5ezq/lQ2/j6hv2e542KQYZwX9d8wKQbSye/OLvpGxlTY6i
 lir2XP1W1zVAz2mAhbOw9PbAKlI24cHZamGWhGp3mkMdNddslYxJ+iAKnX6z0cv+
 KkPEWET4/uyTySygBPnAOMfhTzqMiuwvPswwjYr3TXugQhArnPtOoj1lVLXPArFx
 CqJMrnAy
 =vUtk
 -----END PGP SIGNATURE-----

Merge tag 'v6.13-rc3-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Two fixes for better handling maximum outstanding requests

 - Fix simultaneous negotiate protocol race

* tag 'v6.13-rc3-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: conn lock to serialize smb2 negotiate
  ksmbd: fix broken transfers when exceeding max simultaneous operations
  ksmbd: count all requests in req_running counter
This commit is contained in:
Linus Torvalds 2024-12-19 08:45:37 -08:00
commit 466b2d40f6
6 changed files with 22 additions and 12 deletions

View File

@ -70,7 +70,6 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
atomic_set(&conn->req_running, 0);
atomic_set(&conn->r_count, 0);
atomic_set(&conn->refcnt, 1);
atomic_set(&conn->mux_smb_requests, 0);
conn->total_credits = 1;
conn->outstanding_credits = 0;
@ -120,8 +119,8 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE)
requests_queue = &conn->requests;
atomic_inc(&conn->req_running);
if (requests_queue) {
atomic_inc(&conn->req_running);
spin_lock(&conn->request_lock);
list_add_tail(&work->request_entry, requests_queue);
spin_unlock(&conn->request_lock);
@ -132,11 +131,14 @@ void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
{
struct ksmbd_conn *conn = work->conn;
atomic_dec(&conn->req_running);
if (waitqueue_active(&conn->req_running_q))
wake_up(&conn->req_running_q);
if (list_empty(&work->request_entry) &&
list_empty(&work->async_request_entry))
return;
atomic_dec(&conn->req_running);
spin_lock(&conn->request_lock);
list_del_init(&work->request_entry);
spin_unlock(&conn->request_lock);
@ -308,7 +310,7 @@ int ksmbd_conn_handler_loop(void *p)
{
struct ksmbd_conn *conn = (struct ksmbd_conn *)p;
struct ksmbd_transport *t = conn->transport;
unsigned int pdu_size, max_allowed_pdu_size;
unsigned int pdu_size, max_allowed_pdu_size, max_req;
char hdr_buf[4] = {0,};
int size;
@ -318,6 +320,7 @@ int ksmbd_conn_handler_loop(void *p)
if (t->ops->prepare && t->ops->prepare(t))
goto out;
max_req = server_conf.max_inflight_req;
conn->last_active = jiffies;
set_freezable();
while (ksmbd_conn_alive(conn)) {
@ -327,6 +330,13 @@ int ksmbd_conn_handler_loop(void *p)
kvfree(conn->request_buf);
conn->request_buf = NULL;
recheck:
if (atomic_read(&conn->req_running) + 1 > max_req) {
wait_event_interruptible(conn->req_running_q,
atomic_read(&conn->req_running) < max_req);
goto recheck;
}
size = t->ops->read(t, hdr_buf, sizeof(hdr_buf), -1);
if (size != sizeof(hdr_buf))
break;

View File

@ -107,7 +107,6 @@ struct ksmbd_conn {
__le16 signing_algorithm;
bool binding;
atomic_t refcnt;
atomic_t mux_smb_requests;
};
struct ksmbd_conn_ops {

View File

@ -270,7 +270,6 @@ static void handle_ksmbd_work(struct work_struct *wk)
ksmbd_conn_try_dequeue_request(work);
ksmbd_free_work_struct(work);
atomic_dec(&conn->mux_smb_requests);
/*
* Checking waitqueue to dropping pending requests on
* disconnection. waitqueue_active is safe because it
@ -300,11 +299,6 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
if (err)
return 0;
if (atomic_inc_return(&conn->mux_smb_requests) >= conn->vals->max_credits) {
atomic_dec_return(&conn->mux_smb_requests);
return -ENOSPC;
}
work = ksmbd_alloc_work_struct();
if (!work) {
pr_err("allocation for work failed\n");
@ -367,6 +361,7 @@ static int server_conf_init(void)
server_conf.auth_mechs |= KSMBD_AUTH_KRB5 |
KSMBD_AUTH_MSKRB5;
#endif
server_conf.max_inflight_req = SMB2_MAX_CREDITS;
return 0;
}

View File

@ -42,6 +42,7 @@ struct ksmbd_server_config {
struct smb_sid domain_sid;
unsigned int auth_mechs;
unsigned int max_connections;
unsigned int max_inflight_req;
char *conf[SERVER_CONF_WORK_GROUP + 1];
struct task_struct *dh_task;

View File

@ -1097,6 +1097,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
return rc;
}
ksmbd_conn_lock(conn);
smb2_buf_len = get_rfc1002_len(work->request_buf);
smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects);
if (smb2_neg_size > smb2_buf_len) {
@ -1247,6 +1248,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
ksmbd_conn_set_need_negotiate(conn);
err_out:
ksmbd_conn_unlock(conn);
if (rc)
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;

View File

@ -319,8 +319,11 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)
init_smb2_max_write_size(req->smb2_max_write);
if (req->smb2_max_trans)
init_smb2_max_trans_size(req->smb2_max_trans);
if (req->smb2_max_credits)
if (req->smb2_max_credits) {
init_smb2_max_credits(req->smb2_max_credits);
server_conf.max_inflight_req =
req->smb2_max_credits;
}
if (req->smbd_max_io_size)
init_smbd_max_io_size(req->smbd_max_io_size);