]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
exfat: simplify exfat_lookup()
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 24 Apr 2026 13:29:06 +0000 (22:29 +0900)
committerNamjae Jeon <linkinjeon@kernel.org>
Mon, 15 Jun 2026 10:55:26 +0000 (19:55 +0900)
1) d_splice_alias() handles ERR_PTR() for inode just fine
2) no need to even look for existing aliases in case of directory inodes;
   just punt to d_splice_alias(), it'll do the right thing
3) no need to bother with 'd_unhashed(alias)' case - d_find_alias()
   would've returned that only in case of a directory, and d_splice_alias()
   will handle that just fine on its own.
4) exfat_d_anon_disconn() is entirely pointless now - we only get to
   evaluating it in case dentry->d_parent == alias->d_parent and
   alias being a non-directory.  But in that case IS_ROOT(alias) can't
   possibly be true - that would've reqiured alias == alias->d_parent,
   i.e alias == dentry->d_parent and dentry->d_parent is guaranteed to
   be a directory.  So exfat_d_anon_disconn() would always return false
   when it's called, which makes && !exfat_d_anon_disconn(alias)
   a no-op.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
fs/exfat/namei.c

index 94002e43db08d4f98455cb447d40d0c1017fb735..833b31d0f955da266482124d76785aa02e0904c5 100644 (file)
@@ -705,71 +705,44 @@ static int exfat_find(struct inode *dir, const struct qstr *qname,
        return 0;
 }
 
-static int exfat_d_anon_disconn(struct dentry *dentry)
-{
-       return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED);
-}
-
 static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry,
                unsigned int flags)
 {
        struct super_block *sb = dir->i_sb;
-       struct inode *inode;
+       struct inode *inode = NULL;
        struct dentry *alias;
        struct exfat_dir_entry info;
        int err;
        loff_t i_pos;
-       mode_t i_mode;
 
        mutex_lock(&EXFAT_SB(sb)->s_lock);
        err = exfat_find(dir, &dentry->d_name, &info);
        if (err) {
-               if (err == -ENOENT) {
-                       inode = NULL;
-                       goto out;
-               }
-               goto unlock;
+               if (unlikely(err != -ENOENT))
+                       inode = ERR_PTR(err);
+               goto out;
        }
 
        i_pos = exfat_make_i_pos(&info);
        inode = exfat_build_inode(sb, &info, i_pos);
-       err = PTR_ERR_OR_ZERO(inode);
-       if (err)
-               goto unlock;
+       if (IS_ERR(inode) || S_ISDIR(inode->i_mode))
+               goto out;
 
-       i_mode = inode->i_mode;
        alias = d_find_alias(inode);
 
        /*
         * Checking "alias->d_parent == dentry->d_parent" to make sure
         * FS is not corrupted (especially double linked dir).
         */
-       if (alias && alias->d_parent == dentry->d_parent &&
-                       !exfat_d_anon_disconn(alias)) {
-
+       if (alias && alias->d_parent == dentry->d_parent) {
                /*
-                * Unhashed alias is able to exist because of revalidate()
-                * called by lookup_fast. You can easily make this status
-                * by calling create and lookup concurrently
-                * In such case, we reuse an alias instead of new dentry
+                * This inode has a hashed alias dentry with different
+                * name. This means, the user did ->lookup() by an
+                * another name (longname vs 8.3 alias of it) in past.
+                *
+                * Switch to new one for reason of locality if possible.
                 */
-               if (d_unhashed(alias)) {
-                       WARN_ON(alias->d_name.hash_len !=
-                               dentry->d_name.hash_len);
-                       exfat_info(sb, "rehashed a dentry(%p) in read lookup",
-                                  alias);
-                       d_drop(dentry);
-                       d_rehash(alias);
-               } else if (!S_ISDIR(i_mode)) {
-                       /*
-                        * This inode has non anonymous-DCACHE_DISCONNECTED
-                        * dentry. This means, the user did ->lookup() by an
-                        * another name (longname vs 8.3 alias of it) in past.
-                        *
-                        * Switch to new one for reason of locality if possible.
-                        */
-                       d_move(alias, dentry);
-               }
+               d_move(alias, dentry);
                iput(inode);
                mutex_unlock(&EXFAT_SB(sb)->s_lock);
                return alias;
@@ -781,9 +754,6 @@ out:
                exfat_d_version_set(dentry, inode_query_iversion(dir));
 
        return d_splice_alias(inode, dentry);
-unlock:
-       mutex_unlock(&EXFAT_SB(sb)->s_lock);
-       return ERR_PTR(err);
 }
 
 /* remove an entry, BUT don't truncate */