]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ksmbd: separately allocate ci per dentry
authorNamjae Jeon <linkinjeon@kernel.org>
Mon, 18 Dec 2023 15:34:50 +0000 (00:34 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 Dec 2023 09:41:59 +0000 (10:41 +0100)
[ Upstream commit 4274a9dc6aeb9fea66bffba15697a35ae8983b6a ]

xfstests generic/002 test fail when enabling smb2 leases feature.
This test create hard link file, but removeal failed.
ci has a file open count to count file open through the smb client,
but in the case of hard link files, The allocation of ci per inode
cause incorrectly open count for file deletion. This patch allocate
ci per dentry to counts open counts for hard link.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ksmbd/smb2pdu.c
fs/ksmbd/vfs.c
fs/ksmbd/vfs_cache.c
fs/ksmbd/vfs_cache.h

index e1cb6be9f5a55c9f1793c255f155b9e1e9ca5a4b..5f437073119f5a37f3112dd2e1514d426f9e33b6 100644 (file)
@@ -3036,7 +3036,7 @@ int smb2_open(struct ksmbd_work *work)
                }
        }
 
-       rc = ksmbd_query_inode_status(d_inode(path.dentry->d_parent));
+       rc = ksmbd_query_inode_status(path.dentry->d_parent);
        if (rc == KSMBD_INODE_STATUS_PENDING_DELETE) {
                rc = -EBUSY;
                goto err_out;
index 99fd29761bcafc64e6b5f3a69d74c6d8fe6c7414..a89529b21c866fcdd3670284a818d09caaf2d451 100644 (file)
@@ -719,7 +719,7 @@ retry:
                goto out3;
        }
 
-       parent_fp = ksmbd_lookup_fd_inode(d_inode(old_child->d_parent));
+       parent_fp = ksmbd_lookup_fd_inode(old_child->d_parent);
        if (parent_fp) {
                if (parent_fp->daccess & FILE_DELETE_LE) {
                        pr_err("parent dir is opened with delete access\n");
index 38f414e803adbd23f14a6cfc2cf39434464e7ced..774a387fccced92e49c319d575ff55d3724062e5 100644 (file)
@@ -65,14 +65,14 @@ static unsigned long inode_hash(struct super_block *sb, unsigned long hashval)
        return tmp & inode_hash_mask;
 }
 
-static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode)
+static struct ksmbd_inode *__ksmbd_inode_lookup(struct dentry *de)
 {
        struct hlist_head *head = inode_hashtable +
-               inode_hash(inode->i_sb, inode->i_ino);
+               inode_hash(d_inode(de)->i_sb, (unsigned long)de);
        struct ksmbd_inode *ci = NULL, *ret_ci = NULL;
 
        hlist_for_each_entry(ci, head, m_hash) {
-               if (ci->m_inode == inode) {
+               if (ci->m_de == de) {
                        if (atomic_inc_not_zero(&ci->m_count))
                                ret_ci = ci;
                        break;
@@ -83,26 +83,16 @@ static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode)
 
 static struct ksmbd_inode *ksmbd_inode_lookup(struct ksmbd_file *fp)
 {
-       return __ksmbd_inode_lookup(file_inode(fp->filp));
+       return __ksmbd_inode_lookup(fp->filp->f_path.dentry);
 }
 
-static struct ksmbd_inode *ksmbd_inode_lookup_by_vfsinode(struct inode *inode)
-{
-       struct ksmbd_inode *ci;
-
-       read_lock(&inode_hash_lock);
-       ci = __ksmbd_inode_lookup(inode);
-       read_unlock(&inode_hash_lock);
-       return ci;
-}
-
-int ksmbd_query_inode_status(struct inode *inode)
+int ksmbd_query_inode_status(struct dentry *dentry)
 {
        struct ksmbd_inode *ci;
        int ret = KSMBD_INODE_STATUS_UNKNOWN;
 
        read_lock(&inode_hash_lock);
-       ci = __ksmbd_inode_lookup(inode);
+       ci = __ksmbd_inode_lookup(dentry);
        if (ci) {
                ret = KSMBD_INODE_STATUS_OK;
                if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS))
@@ -142,7 +132,7 @@ void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp,
 static void ksmbd_inode_hash(struct ksmbd_inode *ci)
 {
        struct hlist_head *b = inode_hashtable +
-               inode_hash(ci->m_inode->i_sb, ci->m_inode->i_ino);
+               inode_hash(d_inode(ci->m_de)->i_sb, (unsigned long)ci->m_de);
 
        hlist_add_head(&ci->m_hash, b);
 }
@@ -156,7 +146,6 @@ static void ksmbd_inode_unhash(struct ksmbd_inode *ci)
 
 static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp)
 {
-       ci->m_inode = file_inode(fp->filp);
        atomic_set(&ci->m_count, 1);
        atomic_set(&ci->op_count, 0);
        atomic_set(&ci->sop_count, 0);
@@ -165,6 +154,7 @@ static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp)
        INIT_LIST_HEAD(&ci->m_fp_list);
        INIT_LIST_HEAD(&ci->m_op_list);
        rwlock_init(&ci->m_lock);
+       ci->m_de = fp->filp->f_path.dentry;
        return 0;
 }
 
@@ -487,12 +477,15 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid)
        return fp;
 }
 
-struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode)
+struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry)
 {
        struct ksmbd_file       *lfp;
        struct ksmbd_inode      *ci;
+       struct inode            *inode = d_inode(dentry);
 
-       ci = ksmbd_inode_lookup_by_vfsinode(inode);
+       read_lock(&inode_hash_lock);
+       ci = __ksmbd_inode_lookup(dentry);
+       read_unlock(&inode_hash_lock);
        if (!ci)
                return NULL;
 
index 03d0bf941216f8f5157e1d9f1dca76897a3c51c3..8325cf4527c464c7db83b772e145f01849814faf 100644 (file)
@@ -51,7 +51,7 @@ struct ksmbd_inode {
        atomic_t                        op_count;
        /* opinfo count for streams */
        atomic_t                        sop_count;
-       struct inode                    *m_inode;
+       struct dentry                   *m_de;
        unsigned int                    m_flags;
        struct hlist_node               m_hash;
        struct list_head                m_fp_list;
@@ -140,7 +140,7 @@ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
 void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp);
 struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
 struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
-struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode);
+struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
 unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
 struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
 void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
@@ -164,7 +164,7 @@ enum KSMBD_INODE_STATUS {
        KSMBD_INODE_STATUS_PENDING_DELETE,
 };
 
-int ksmbd_query_inode_status(struct inode *inode);
+int ksmbd_query_inode_status(struct dentry *dentry);
 bool ksmbd_inode_pending_delete(struct ksmbd_file *fp);
 void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp);
 void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp);