Commit 466b2d40 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents eabcdba3 fe4ed2f0
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -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;

	if (requests_queue) {
	atomic_inc(&conn->req_running);
	if (requests_queue) {
		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;
+0 −1
Original line number Diff line number Diff line
@@ -107,7 +107,6 @@ struct ksmbd_conn {
	__le16				signing_algorithm;
	bool				binding;
	atomic_t			refcnt;
	atomic_t			mux_smb_requests;
};

struct ksmbd_conn_ops {
+1 −6
Original line number Diff line number Diff line
@@ -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;
}

+1 −0
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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;

Loading