summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/smb/server/mgmt/tree_connect.c33
-rw-r--r--fs/smb/server/mgmt/user_session.c4
-rw-r--r--fs/smb/server/mgmt/user_session.h2
-rw-r--r--fs/smb/server/smb2pdu.c10
4 files changed, 30 insertions, 19 deletions
diff --git a/fs/smb/server/mgmt/tree_connect.c b/fs/smb/server/mgmt/tree_connect.c
index 62b97936b545..57dd47ef688c 100644
--- a/fs/smb/server/mgmt/tree_connect.c
+++ b/fs/smb/server/mgmt/tree_connect.c
@@ -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,
- struct ksmbd_tree_connect *tree_conn)
+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;
}
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
index c35083f576c3..b02fa4dcc2d6 100644
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -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);
diff --git a/fs/smb/server/mgmt/user_session.h b/fs/smb/server/mgmt/user_session.h
index d94f5e128a9b..6aebd385be84 100644
--- a/fs/smb/server/mgmt/user_session.h
+++ b/fs/smb/server/mgmt/user_session.h
@@ -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;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 3efcc7da1b9f..cbb31efdbaa2 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -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) {