fs/smb/server/connection.c

Source file repositories/reference/linux-study-clean/fs/smb/server/connection.c

File Facts

System
Linux kernel
Corpus path
fs/smb/server/connection.c
Extension
.c
Size
16974 bytes
Lines
692
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

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
 *
 * @conn:	connection instance to be cleaned up
 *
 * During the thread termination, the corresponding conn instance
 * resources(sock/memory) are released and finally the conn object is freed.

Annotation

Implementation Notes