From: Al Viro Date: Fri, 24 Apr 2026 13:29:06 +0000 (+0900) Subject: exfat: simplify exfat_lookup() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=623f0aa1eca5c2a94ca1e4e5de719d062eac3b6c;p=thirdparty%2Flinux.git exfat: simplify exfat_lookup() 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 Reviewed-by: Sungjong Seo Signed-off-by: Namjae Jeon --- diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c index 94002e43db08..833b31d0f955 100644 --- a/fs/exfat/namei.c +++ b/fs/exfat/namei.c @@ -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 */