ksmbd: separately allocate ci per dentry
authorNamjae Jeon <linkinjeon@kernel.org>
Sun, 31 Dec 2023 07:19:09 +0000 (16:19 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Jan 2024 14:19:39 +0000 (15:19 +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: Sasha Levin <sashal@kernel.org>
fs/smb/server/smb2pdu.c
fs/smb/server/vfs.c
fs/smb/server/vfs_cache.c
fs/smb/server/vfs_cache.h

index 2b248d45d40ae3bb9a4c931a38502f70ecadc2f0..28b61dad27498a8aea7e8dfe4879ece9742fbb80 100644 (file)
@@ -3039,7 +3039,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 533257b46fc17105893d2fec01fa5cf1876162b3..9091dcd7a3102c82a24d04948847ed5edbb67d45 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 c91eac6514dd95e732e6cdc74ee9a5422dc06eec..ddf233994ddbbf37c1657b925961a7f8be94f4f0 100644 (file)
@@ -66,14 +66,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;
@@ -84,26 +84,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))
@@ -143,7 +133,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);
 }
@@ -157,7 +147,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);
@@ -166,6 +155,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;
 }
 
@@ -488,12 +478,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);