]> www.infradead.org Git - users/willy/pagecache.git/commitdiff
generic_ci_d_compare(): use shortname_storage
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 23 Dec 2024 07:23:00 +0000 (02:23 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 28 Jan 2025 00:24:43 +0000 (19:24 -0500)
... and check the "name might be unstable" predicate
the right way.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Gabriel Krisman Bertazi <gabriel@krisman.be>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/libfs.c

index 748ac59231547c29abcbade3fa025e3b00533d8b..3ad1b1b7fed6e7433ac9997d7f34429d58f97b79 100644 (file)
@@ -1789,7 +1789,7 @@ int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
 {
        const struct dentry *parent;
        const struct inode *dir;
-       char strbuf[DNAME_INLINE_LEN];
+       union shortname_store strbuf;
        struct qstr qstr;
 
        /*
@@ -1809,22 +1809,23 @@ int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
        if (!dir || !IS_CASEFOLDED(dir))
                return 1;
 
+       qstr.len = len;
+       qstr.name = str;
        /*
         * 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.
         * However, it's unsafe to call utf8_strncasecmp() with an unstable
         * string.  Therefore, we have to copy the name into a temporary buffer.
+        * As above, len is guaranteed to match str, so the shortname case
+        * is exactly when str points to ->d_shortname.
         */
-       if (len <= DNAME_INLINE_LEN - 1) {
-               memcpy(strbuf, str, len);
-               strbuf[len] = 0;
-               str = strbuf;
+       if (qstr.name == dentry->d_shortname.string) {
+               strbuf = dentry->d_shortname; // NUL is guaranteed to be in there
+               qstr.name = strbuf.string;
                /* prevent compiler from optimizing out the temporary buffer */
                barrier();
        }
-       qstr.len = len;
-       qstr.name = str;
 
        return utf8_strncasecmp(dentry->d_sb->s_encoding, name, &qstr);
 }