ksmbd: use rwsem instead of rwlock for lease break
authorNamjae Jeon <linkinjeon@kernel.org>
Thu, 2 May 2024 01:07:50 +0000 (10:07 +0900)
committerSteve French <stfrench@microsoft.com>
Sun, 5 May 2024 04:53:36 +0000 (23:53 -0500)
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.

Cc: stable@vger.kernel.org
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/oplock.c
fs/smb/server/smb2pdu.c
fs/smb/server/smb_common.c
fs/smb/server/vfs_cache.c
fs/smb/server/vfs_cache.h

index 6fd8cb7..c2abf10 100644 (file)
@@ -207,9 +207,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)
@@ -221,9 +221,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)
@@ -526,21 +526,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) +
@@ -570,9 +567,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;
 }
@@ -1114,7 +1110,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;
@@ -1132,13 +1128,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);
 }
@@ -1159,7 +1153,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;
@@ -1173,13 +1167,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);
 }
index 3022916..b6c5a8e 100644 (file)
@@ -3376,9 +3376,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)) {
index fcaf373..474dadf 100644 (file)
@@ -646,7 +646,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;
@@ -722,7 +722,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;
 }
index 030f707..6cb599c 100644 (file)
@@ -165,7 +165,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;
 }
@@ -261,14 +261,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)) {
                        ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING);
-                       write_unlock(&ci->m_lock);
+                       up_write(&ci->m_lock);
                        ksmbd_vfs_unlink(filp);
-                       write_lock(&ci->m_lock);
+                       down_write(&ci->m_lock);
                }
-               write_unlock(&ci->m_lock);
+               up_write(&ci->m_lock);
 
                ksmbd_inode_free(ci);
        }
@@ -289,9 +289,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);
@@ -523,17 +523,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;
 }
 
@@ -705,13 +705,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;
@@ -801,13 +801,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)) {
index ed44fb4..5a225e7 100644 (file)
@@ -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 */