From 977866e0d338515ea95f7168286a01796b5a3146 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 3 May 2024 22:53:48 +0900 Subject: [PATCH] ksmbd: use rwsem instead of rwlock for lease break lease break wait for lease break acknowledgment. rwsem is more suitable than unlock while traversing the list for parent lease break in ->m_op_list. Signed-off-by: Namjae Jeon --- oplock.c | 30 +++++++++++------------------- smb1pdu.c | 16 ++++++++-------- smb2pdu.c | 4 ++-- smb_common.c | 4 ++-- vfs_cache.c | 28 ++++++++++++++-------------- vfs_cache.h | 2 +- 6 files changed, 38 insertions(+), 46 deletions(-) diff --git a/oplock.c b/oplock.c index ba697ea67..cb1a8987a 100644 --- a/oplock.c +++ b/oplock.c @@ -213,9 +213,9 @@ static void opinfo_add(struct oplock_info *opinfo) { struct ksmbd_inode *ci = opinfo->o_fp->f_ci; - write_lock(&ci->m_lock); + down_write(&ci->m_lock); list_add_rcu(&opinfo->op_entry, &ci->m_op_list); - write_unlock(&ci->m_lock); + up_write(&ci->m_lock); } static void opinfo_del(struct oplock_info *opinfo) @@ -227,9 +227,9 @@ static void opinfo_del(struct oplock_info *opinfo) lease_del_list(opinfo); write_unlock(&lease_list_lock); } - write_lock(&ci->m_lock); + down_write(&ci->m_lock); list_del_rcu(&opinfo->op_entry); - write_unlock(&ci->m_lock); + up_write(&ci->m_lock); } static unsigned long opinfo_count(struct ksmbd_file *fp) @@ -625,21 +625,18 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci, * Compare lease key and client_guid to know request from same owner * of same client */ - read_lock(&ci->m_lock); + down_read(&ci->m_lock); list_for_each_entry(opinfo, &ci->m_op_list, op_entry) { if (!opinfo->is_lease || !opinfo->conn) continue; - read_unlock(&ci->m_lock); lease = opinfo->o_lease; ret = compare_guid_key(opinfo, client_guid, lctx->lease_key); if (ret) { m_opinfo = opinfo; /* skip upgrading lease about breaking lease */ - if (atomic_read(&opinfo->breaking_cnt)) { - read_lock(&ci->m_lock); + if (atomic_read(&opinfo->breaking_cnt)) continue; - } /* upgrading lease */ if ((atomic_read(&ci->op_count) + @@ -669,9 +666,8 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci, lease_none_upgrade(opinfo, lctx->req_state); } } - read_lock(&ci->m_lock); } - read_unlock(&ci->m_lock); + up_read(&ci->m_lock); return m_opinfo; } @@ -1330,7 +1326,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, if (!p_ci) return; - read_lock(&p_ci->m_lock); + down_read(&p_ci->m_lock); list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) { if (opinfo->conn == NULL || !opinfo->is_lease) continue; @@ -1348,13 +1344,11 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, continue; } - read_unlock(&p_ci->m_lock); oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE); opinfo_conn_put(opinfo); - read_lock(&p_ci->m_lock); } } - read_unlock(&p_ci->m_lock); + up_read(&p_ci->m_lock); ksmbd_inode_put(p_ci); } @@ -1375,7 +1369,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) if (!p_ci) return; - read_lock(&p_ci->m_lock); + down_read(&p_ci->m_lock); list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) { if (opinfo->conn == NULL || !opinfo->is_lease) continue; @@ -1389,13 +1383,11 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) atomic_dec(&opinfo->conn->r_count); continue; } - read_unlock(&p_ci->m_lock); oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE); opinfo_conn_put(opinfo); - read_lock(&p_ci->m_lock); } } - read_unlock(&p_ci->m_lock); + up_read(&p_ci->m_lock); ksmbd_inode_put(p_ci); } diff --git a/smb1pdu.c b/smb1pdu.c index 677cdee93..9f3bf136f 100644 --- a/smb1pdu.c +++ b/smb1pdu.c @@ -2642,9 +2642,9 @@ int smb_nt_create_andx(struct ksmbd_work *work) fp->saccess = req->ShareAccess; fp->pid = le16_to_cpu(req->hdr.Pid); - write_lock(&fp->f_ci->m_lock); + down_write(&fp->f_ci->m_lock); list_add(&fp->node, &fp->f_ci->m_fp_list); - write_unlock(&fp->f_ci->m_lock); + up_write(&fp->f_ci->m_lock); share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp); if (smb1_oplock_enable && @@ -5098,9 +5098,9 @@ static int smb_posix_open(struct ksmbd_work *work) } fp->pid = le16_to_cpu(pSMB_req->hdr.Pid); - write_lock(&fp->f_ci->m_lock); + down_write(&fp->f_ci->m_lock); list_add(&fp->node, &fp->f_ci->m_fp_list); - write_unlock(&fp->f_ci->m_lock); + up_write(&fp->f_ci->m_lock); if (smb1_oplock_enable && test_share_config_flag(work->tcon->share_conf, @@ -6163,9 +6163,9 @@ static int find_first(struct ksmbd_work *work) path_put(&parent_path); #endif - write_lock(&dir_fp->f_ci->m_lock); + down_write(&dir_fp->f_ci->m_lock); list_add(&dir_fp->node, &dir_fp->f_ci->m_fp_list); - write_unlock(&dir_fp->f_ci->m_lock); + up_write(&dir_fp->f_ci->m_lock); set_ctx_actor(&dir_fp->readdir_data.ctx, ksmbd_fill_dirent); dir_fp->readdir_data.dirent = (void *)__get_free_page(GFP_KERNEL); @@ -8416,9 +8416,9 @@ int smb_open_andx(struct ksmbd_work *work) } fp->pid = le16_to_cpu(req->hdr.Pid); - write_lock(&fp->f_ci->m_lock); + down_write(&fp->f_ci->m_lock); list_add(&fp->node, &fp->f_ci->m_fp_list); - write_unlock(&fp->f_ci->m_lock); + up_write(&fp->f_ci->m_lock); share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp); if (smb1_oplock_enable && diff --git a/smb2pdu.c b/smb2pdu.c index 8f947f810..5672b31ff 100644 --- a/smb2pdu.c +++ b/smb2pdu.c @@ -3552,9 +3552,9 @@ int smb2_open(struct ksmbd_work *work) * after daccess, saccess, attrib_only, and stream are * initialized. */ - write_lock(&fp->f_ci->m_lock); + down_write(&fp->f_ci->m_lock); list_add(&fp->node, &fp->f_ci->m_fp_list); - write_unlock(&fp->f_ci->m_lock); + up_write(&fp->f_ci->m_lock); /* Check delete pending among previous fp before oplock break */ if (ksmbd_inode_pending_delete(fp)) { diff --git a/smb_common.c b/smb_common.c index 1e965351d..5202d2b1d 100644 --- a/smb_common.c +++ b/smb_common.c @@ -691,7 +691,7 @@ int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp) * Lookup fp in master fp list, and check desired access and * shared mode between previous open and current open. */ - read_lock(&curr_fp->f_ci->m_lock); + down_read(&curr_fp->f_ci->m_lock); list_for_each_entry(prev_fp, &curr_fp->f_ci->m_fp_list, node) { if (file_inode(filp) != file_inode(prev_fp->filp)) continue; @@ -767,7 +767,7 @@ int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp) break; } } - read_unlock(&curr_fp->f_ci->m_lock); + up_read(&curr_fp->f_ci->m_lock); return rc; } diff --git a/vfs_cache.c b/vfs_cache.c index c0a020349..9628e02ff 100644 --- a/vfs_cache.c +++ b/vfs_cache.c @@ -168,7 +168,7 @@ static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp) ci->m_fattr = 0; INIT_LIST_HEAD(&ci->m_fp_list); INIT_LIST_HEAD(&ci->m_op_list); - rwlock_init(&ci->m_lock); + init_rwsem(&ci->m_lock); ci->m_de = fp->filp->f_path.dentry; return 0; } @@ -271,14 +271,14 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp) } if (atomic_dec_and_test(&ci->m_count)) { - write_lock(&ci->m_lock); + down_write(&ci->m_lock); if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) { #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) dentry = filp->f_path.dentry; dir = dentry->d_parent; #endif ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING); - write_unlock(&ci->m_lock); + up_write(&ci->m_lock); #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) ksmbd_vfs_unlink(filp); @@ -288,9 +288,9 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp) #else ksmbd_vfs_unlink(file_mnt_user_ns(filp), dir, dentry); #endif - write_lock(&ci->m_lock); + down_write(&ci->m_lock); } - write_unlock(&ci->m_lock); + up_write(&ci->m_lock); ksmbd_inode_free(ci); } @@ -311,9 +311,9 @@ static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp if (!has_file_id(fp->volatile_id)) return; - write_lock(&fp->f_ci->m_lock); + down_write(&fp->f_ci->m_lock); list_del_init(&fp->node); - write_unlock(&fp->f_ci->m_lock); + up_write(&fp->f_ci->m_lock); write_lock(&ft->lock); idr_remove(ft->idr, fp->volatile_id); @@ -577,17 +577,17 @@ struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry) if (!ci) return NULL; - read_lock(&ci->m_lock); + down_read(&ci->m_lock); list_for_each_entry(lfp, &ci->m_fp_list, node) { if (inode == file_inode(lfp->filp)) { atomic_dec(&ci->m_count); lfp = ksmbd_fp_get(lfp); - read_unlock(&ci->m_lock); + up_read(&ci->m_lock); return lfp; } } atomic_dec(&ci->m_count); - read_unlock(&ci->m_lock); + up_read(&ci->m_lock); return NULL; } @@ -765,13 +765,13 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon, conn = fp->conn; ci = fp->f_ci; - write_lock(&ci->m_lock); + down_write(&ci->m_lock); list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { if (op->conn != conn) continue; op->conn = NULL; } - write_unlock(&ci->m_lock); + up_write(&ci->m_lock); fp->conn = NULL; fp->tcon = NULL; @@ -877,13 +877,13 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp) fp->tcon = work->tcon; ci = fp->f_ci; - write_lock(&ci->m_lock); + down_write(&ci->m_lock); list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { if (op->conn) continue; op->conn = fp->conn; } - write_unlock(&ci->m_lock); + up_write(&ci->m_lock); __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID); if (!has_file_id(fp->volatile_id)) { diff --git a/vfs_cache.h b/vfs_cache.h index 920d49aa3..87af165d6 100644 --- a/vfs_cache.h +++ b/vfs_cache.h @@ -47,7 +47,7 @@ struct stream { }; struct ksmbd_inode { - rwlock_t m_lock; + struct rw_semaphore m_lock; atomic_t m_count; atomic_t op_count; /* opinfo count for streams */