All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] libfs: Attempt exact-match comparison first during casefold lookup
@ 2024-01-17 22:28 Gabriel Krisman Bertazi
  2024-01-17 22:38 ` Al Viro
  0 siblings, 1 reply; 7+ messages in thread
From: Gabriel Krisman Bertazi @ 2024-01-17 22:28 UTC (permalink / raw)
  To: ebiggers, tytso
  Cc: linux-fsdevel, viro, jaegeuk, Gabriel Krisman Bertazi,
	Linus Torvalds

Casefolded comparisons are (obviously) way more costly than a simple
memcmp.  Try the case-sensitive comparison first, falling-back to the
case-insensitive lookup only when needed.  This allows any exact-match
lookup to complete without having to walk the utf8 trie.

Note that, for strict mode, generic_ci_d_compare used to reject an
invalid UTF-8 string, which would now be considered valid if it
exact-matches the disk-name.  But, if that is the case, the filesystem
is corrupt.  More than that, it really doesn't matter in practice,
because the name-under-lookup will have already been rejected by
generic_ci_d_hash and we won't even get here.

Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
 fs/libfs.c | 40 ++++++++++++++++++++++++----------------
 1 file changed, 24 insertions(+), 16 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index eec6031b0155..d17a8adb4a35 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -1704,17 +1704,28 @@ bool is_empty_dir_inode(struct inode *inode)
 static int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
 				const char *str, const struct qstr *name)
 {
-	const struct dentry *parent = READ_ONCE(dentry->d_parent);
-	const struct inode *dir = READ_ONCE(parent->d_inode);
-	const struct super_block *sb = dentry->d_sb;
-	const struct unicode_map *um = sb->s_encoding;
-	struct qstr qstr = QSTR_INIT(str, len);
+	const struct dentry *parent;
+	const struct inode *dir;
 	char strbuf[DNAME_INLINE_LEN];
+	struct qstr qstr;
 	int ret;
 
+	/*
+	 * Attempt a case-sensitive match first. It is cheaper and
+	 * should cover most lookups, including all the sane
+	 * applications that expect a case-sensitive filesystem.
+	 */
+	if (len == name->len && !memcmp(str, name->name, len))
+		return 0;
+
+	parent = READ_ONCE(dentry->d_parent);
+	dir = READ_ONCE(parent->d_inode);
 	if (!dir || !IS_CASEFOLDED(dir))
-		goto fallback;
+		return 1;
+
 	/*
+	 * Finally, try the case-insensitive match.
+	 *
 	 * If the dentry name is stored in-line, then it may be concurrently
 	 * modified by a rename.  If this happens, the VFS will eventually retry
 	 * the lookup, so it doesn't matter what ->d_compare() returns.
@@ -1724,20 +1735,17 @@ static int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
 	if (len <= DNAME_INLINE_LEN - 1) {
 		memcpy(strbuf, str, len);
 		strbuf[len] = 0;
-		qstr.name = strbuf;
+		str = strbuf;
 		/* prevent compiler from optimizing out the temporary buffer */
 		barrier();
 	}
-	ret = utf8_strncasecmp(um, name, &qstr);
-	if (ret >= 0)
-		return ret;
-
-	if (sb_has_strict_encoding(sb))
+	qstr.len = len;
+	qstr.name = str;
+	ret = utf8_strncasecmp(dentry->d_sb->s_encoding, name, &qstr);
+	if (ret < 0)
 		return -EINVAL;
-fallback:
-	if (len != name->len)
-		return 1;
-	return !!memcmp(str, name->name, len);
+
+	return ret;
 }
 
 /**
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2024-01-18 15:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-17 22:28 [PATCH] libfs: Attempt exact-match comparison first during casefold lookup Gabriel Krisman Bertazi
2024-01-17 22:38 ` Al Viro
2024-01-18  0:02   ` Gabriel Krisman Bertazi
2024-01-18  0:40     ` Linus Torvalds
2024-01-18  2:05       ` Theodore Ts'o
2024-01-18  2:33         ` Linus Torvalds
2024-01-18 15:06           ` Gabriel Krisman Bertazi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.