Commit 31b9028c authored by Namjae Jeon's avatar Namjae Jeon Committed by Steve French
Browse files

ksmbd: convert tree_conns_lock to rw_semaphore



Converts tree_conns_lock to an rw_semaphore to allow sleeping while
the lock is held. Additionally, it simplifies the locking logic in
ksmbd_tree_conn_session_logoff() and introduces
__ksmbd_tree_conn_disconnect() to avoid redundant locking.

Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 00806087
Loading
Loading
Loading
Loading
+21 −12
Original line number Diff line number Diff line
@@ -80,8 +80,10 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name)
	status.tree_conn = tree_conn;
	atomic_set(&tree_conn->refcount, 1);

	down_write(&sess->tree_conns_lock);
	ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn,
			      KSMBD_DEFAULT_GFP));
	up_write(&sess->tree_conns_lock);
	if (ret) {
		status.ret = -ENOMEM;
		goto out_error;
@@ -105,15 +107,11 @@ void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon)
		kfree(tcon);
}

int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
static int __ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
					struct ksmbd_tree_connect *tree_conn)
{
	int ret;

	write_lock(&sess->tree_conns_lock);
	xa_erase(&sess->tree_conns, tree_conn->id);
	write_unlock(&sess->tree_conns_lock);

	ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id);
	ksmbd_release_tree_conn_id(sess, tree_conn->id);
	ksmbd_share_config_put(tree_conn->share_conf);
@@ -123,12 +121,22 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
	return ret;
}

int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
			       struct ksmbd_tree_connect *tree_conn)
{
	down_write(&sess->tree_conns_lock);
	xa_erase(&sess->tree_conns, tree_conn->id);
	up_write(&sess->tree_conns_lock);

	return __ksmbd_tree_conn_disconnect(sess, tree_conn);
}

struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
						  unsigned int id)
{
	struct ksmbd_tree_connect *tcon;

	read_lock(&sess->tree_conns_lock);
	down_read(&sess->tree_conns_lock);
	tcon = xa_load(&sess->tree_conns, id);
	if (tcon) {
		if (tcon->t_state != TREE_CONNECTED)
@@ -136,7 +144,7 @@ struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
		else if (!atomic_inc_not_zero(&tcon->refcount))
			tcon = NULL;
	}
	read_unlock(&sess->tree_conns_lock);
	up_read(&sess->tree_conns_lock);

	return tcon;
}
@@ -150,18 +158,19 @@ int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess)
	if (!sess)
		return -EINVAL;

	down_write(&sess->tree_conns_lock);
	xa_for_each(&sess->tree_conns, id, tc) {
		write_lock(&sess->tree_conns_lock);
		if (tc->t_state == TREE_DISCONNECTED) {
			write_unlock(&sess->tree_conns_lock);
			ret = -ENOENT;
			continue;
		}
		tc->t_state = TREE_DISCONNECTED;
		write_unlock(&sess->tree_conns_lock);

		ret |= ksmbd_tree_conn_disconnect(sess, tc);
		xa_erase(&sess->tree_conns, tc->id);
		ret |= __ksmbd_tree_conn_disconnect(sess, tc);
	}
	xa_destroy(&sess->tree_conns);
	up_write(&sess->tree_conns_lock);

	return ret;
}
+3 −1
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ static int show_proc_session(struct seq_file *m, void *v)
	seq_printf(m, "%-20s\t%d\n", "channels", i);

	i = 0;
	down_read(&sess->tree_conns_lock);
	xa_for_each(&sess->tree_conns, id, tree_conn) {
		share_conf = tree_conn->share_conf;
		seq_printf(m, "%-20s\t%s\t%8d", "share",
@@ -145,6 +146,7 @@ static int show_proc_session(struct seq_file *m, void *v)
			seq_printf(m, " %s ", "disk");
		seq_putc(m, '\n');
	}
	up_read(&sess->tree_conns_lock);

	ksmbd_user_session_put(sess);
	return 0;
@@ -673,8 +675,8 @@ static struct ksmbd_session *__session_create(int protocol)
	xa_init(&sess->ksmbd_chann_list);
	xa_init(&sess->rpc_handle_list);
	sess->sequence_number = 1;
	rwlock_init(&sess->tree_conns_lock);
	atomic_set(&sess->refcnt, 2);
	init_rwsem(&sess->tree_conns_lock);
	init_rwsem(&sess->rpc_lock);
	init_rwsem(&sess->chann_lock);

+1 −1
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ struct ksmbd_session {

	struct ksmbd_file_table		file_table;
	unsigned long			last_active;
	rwlock_t			tree_conns_lock;
	struct rw_semaphore		tree_conns_lock;

#ifdef CONFIG_PROC_FS
	struct proc_dir_entry		*proc_entry;
+5 −5
Original line number Diff line number Diff line
@@ -2037,9 +2037,9 @@ int smb2_tree_connect(struct ksmbd_work *work)
	if (conn->posix_ext_supported)
		status.tree_conn->posix_extensions = true;

	write_lock(&sess->tree_conns_lock);
	down_write(&sess->tree_conns_lock);
	status.tree_conn->t_state = TREE_CONNECTED;
	write_unlock(&sess->tree_conns_lock);
	up_write(&sess->tree_conns_lock);
	rsp->StructureSize = cpu_to_le16(16);
out_err1:
	if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && share &&
@@ -2193,16 +2193,16 @@ int smb2_tree_disconnect(struct ksmbd_work *work)

	ksmbd_close_tree_conn_fds(work);

	write_lock(&sess->tree_conns_lock);
	down_write(&sess->tree_conns_lock);
	if (tcon->t_state == TREE_DISCONNECTED) {
		write_unlock(&sess->tree_conns_lock);
		up_write(&sess->tree_conns_lock);
		rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
		err = -ENOENT;
		goto err_out;
	}

	tcon->t_state = TREE_DISCONNECTED;
	write_unlock(&sess->tree_conns_lock);
	up_write(&sess->tree_conns_lock);

	err = ksmbd_tree_conn_disconnect(sess, tcon);
	if (err) {