Commit 8ab992f8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v7.1-rc3-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Fix memory leak in connection free

 - Fix inherited ACL ACE validation

 - Minor cleanup

 - Fix for share config

 - Fix durable handle cleanup race

 - Fix close_file_table_ids in session teardown

 - smbdirect fixes:
    - Fix memory region registration
    - Two fixes for out-of-tree builds

* tag 'v7.1-rc3-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: validate inherited ACE SID length
  ksmbd: fix kernel-doc warnings from ksmbd_conn_get/put()
  ksmbd: fail share config requests when path allocation fails
  ksmbd: close durable scavenger races against m_fp_list lookups
  ksmbd: harden file lifetime during session teardown
  ksmbd: centralize ksmbd_conn final release to plug transport leak
  smb: smbdirect: fix MR registration for coalesced SG lists
  smb: smbdirect: introduce and use include/linux/smbdirect.h
  smb: smbdirect: make use of DEFAULT_SYMBOL_NAMESPACE and EXPORT_SYMBOL_GPL
parents b625e47f 996454bc
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -24650,6 +24650,7 @@ S: Maintained
F:	fs/smb/client/smbdirect.*
F:	fs/smb/smbdirect/
F:	fs/smb/server/transport_rdma.*
F:	include/linux/smbdirect.h
SMC91x ETHERNET DRIVER
M:	Nicolas Pitre <nico@fluxnic.net>
+2 −1
Original line number Diff line number Diff line
@@ -9,7 +9,6 @@
#include "cifs_debug.h"
#include "cifsproto.h"
#include "smb2proto.h"
#include "../smbdirect/public.h"

/* Port numbers for SMBD transport */
#define SMB_PORT	445
@@ -558,3 +557,5 @@ void smbd_debug_proc_show(struct TCP_Server_Info *server, struct seq_file *m)
						    server->rdma_readwrite_threshold,
						    m);
}

MODULE_IMPORT_NS("SMBDIRECT");
+1 −1
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@

#include "cifsglob.h"

#include "../smbdirect/smbdirect.h"
#include <linux/smbdirect.h>

extern int rdma_readwrite_threshold;
extern int smbd_max_frmr_depth;
+90 −15
Original line number Diff line number Diff line
@@ -79,6 +79,85 @@ static int create_proc_clients(void) { return 0; }
static void delete_proc_clients(void) {}
#endif

static struct workqueue_struct *ksmbd_conn_wq;

int ksmbd_conn_wq_init(void)
{
	ksmbd_conn_wq = alloc_workqueue("ksmbd-conn-release",
					WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
	if (!ksmbd_conn_wq)
		return -ENOMEM;
	return 0;
}

void ksmbd_conn_wq_destroy(void)
{
	if (ksmbd_conn_wq) {
		destroy_workqueue(ksmbd_conn_wq);
		ksmbd_conn_wq = NULL;
	}
}

/*
 * __ksmbd_conn_release_work() - perform the final, once-per-struct cleanup
 * of a ksmbd_conn whose refcount has just dropped to zero.
 *
 * This is the common release path used by ksmbd_conn_put() for the embedded
 * state that outlives the connection thread: async_ida and the attached
 * transport (which owns the socket and iov for TCP).  Called from a workqueue
 * so that sleep-allowed teardown (sock_release -> tcp_close ->
 * lock_sock_nested) never runs from an RCU softirq callback (free_opinfo_rcu)
 * or any other non-sleeping putter context.
 */
static void __ksmbd_conn_release_work(struct work_struct *work)
{
	struct ksmbd_conn *conn =
		container_of(work, struct ksmbd_conn, release_work);

	ida_destroy(&conn->async_ida);
	conn->transport->ops->free_transport(conn->transport);
	kfree(conn);
}

/**
 * ksmbd_conn_get() - take a reference on @conn and return it.
 *
 * @conn: connection instance to get a reference to
 *
 * Returns @conn unchanged so callers can write
 * "fp->conn = ksmbd_conn_get(work->conn);" in one expression.  Returns NULL
 * if @conn is NULL.
 */
struct ksmbd_conn *ksmbd_conn_get(struct ksmbd_conn *conn)
{
	if (!conn)
		return NULL;

	atomic_inc(&conn->refcnt);
	return conn;
}

/**
 * ksmbd_conn_put() - drop a reference and, if it was the last, queue the
 * release onto ksmbd_conn_wq so it runs from process context.
 *
 * @conn: connection instance to put a reference to
 *
 * Callable from any context including RCU softirq callbacks and non-sleeping
 * locks; the actual release is deferred to the workqueue.  ksmbd_conn_wq is
 * created in ksmbd_server_init() before any conn can be allocated and is
 * destroyed in ksmbd_server_exit() after rcu_barrier(), so it is always
 * non-NULL while a conn reference is held.
 */
void ksmbd_conn_put(struct ksmbd_conn *conn)
{
	if (!conn)
		return;

	if (atomic_dec_and_test(&conn->refcnt))
		queue_work(ksmbd_conn_wq, &conn->release_work);
}

/**
 * ksmbd_conn_free() - free resources of the connection instance
 *
@@ -93,23 +172,19 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
	hash_del(&conn->hlist);
	up_write(&conn_list_lock);

	/*
	 * request_buf / preauth_info / mechToken are only ever accessed by the
	 * connection handler thread that owns @conn.  ksmbd_conn_free() is
	 * called from the transport free_transport() path when that thread is
	 * exiting, so it is safe to release them unconditionally even when
	 * ksmbd_conn_put() below is not the final putter (oplock / ksmbd_file
	 * holders only retain the conn pointer, not these per-thread buffers).
	 */
	xa_destroy(&conn->sessions);
	kvfree(conn->request_buf);
	kfree(conn->preauth_info);
	kfree(conn->mechToken);
	if (atomic_dec_and_test(&conn->refcnt)) {
		/*
		 * async_ida is embedded in struct ksmbd_conn, so pair
		 * ida_destroy() with the final kfree() rather than with
		 * the unconditional field teardown above.  This keeps
		 * the IDA valid for the entire lifetime of the struct,
		 * even while other refcount holders (oplock / vfs
		 * durable handles) still reference the connection.
		 */
		ida_destroy(&conn->async_ida);
		conn->transport->ops->free_transport(conn->transport);
		kfree(conn);
	}
	ksmbd_conn_put(conn);
}

/**
@@ -136,6 +211,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
		conn->um = ERR_PTR(-EOPNOTSUPP);
	if (IS_ERR(conn->um))
		conn->um = NULL;
	INIT_WORK(&conn->release_work, __ksmbd_conn_release_work);
	atomic_set(&conn->req_running, 0);
	atomic_set(&conn->r_count, 0);
	atomic_set(&conn->refcnt, 1);
@@ -512,8 +588,7 @@ void ksmbd_conn_r_count_dec(struct ksmbd_conn *conn)
	if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
		wake_up(&conn->r_count_q);

	if (atomic_dec_and_test(&conn->refcnt))
		kfree(conn);
	ksmbd_conn_put(conn);
}

int ksmbd_conn_transport_init(void)
+6 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/kthread.h>
#include <linux/nls.h>
#include <linux/unicode.h>
#include <linux/workqueue.h>

#include "smb_common.h"
#include "ksmbd_work.h"
@@ -120,6 +121,7 @@ struct ksmbd_conn {
	bool				binding;
	atomic_t			refcnt;
	bool				is_aapl;
	struct work_struct		release_work;
};

struct ksmbd_conn_ops {
@@ -164,6 +166,10 @@ void ksmbd_conn_wait_idle(struct ksmbd_conn *conn);
int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id);
struct ksmbd_conn *ksmbd_conn_alloc(void);
void ksmbd_conn_free(struct ksmbd_conn *conn);
struct ksmbd_conn *ksmbd_conn_get(struct ksmbd_conn *conn);
void ksmbd_conn_put(struct ksmbd_conn *conn);
int ksmbd_conn_wq_init(void);
void ksmbd_conn_wq_destroy(void);
bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c);
int ksmbd_conn_write(struct ksmbd_work *work);
int ksmbd_conn_rdma_read(struct ksmbd_conn *conn,
Loading