Skip to content

Commit 09406ad

Browse files
committed
Merge tag 'for-next-6.9' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/krisman/unicode into vfs.misc
Merge case-insensitive updates from Gabriel Krisman Bertazi: - Patch case-insensitive lookup by trying the case-exact comparison first, before falling back to costly utf8 casefolded comparison. - Fix to forbid using a case-insensitive directory as part of an overlayfs mount. - Patchset to ensure d_op are set at d_alloc time for fscrypt and casefold volumes, ensuring filesystem dentries will all have the correct ops, whether they come from a lookup or not. * tag 'for-next-6.9' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/krisman/unicode: libfs: Drop generic_set_encrypted_ci_d_ops ubifs: Configure dentry operations at dentry-creation time f2fs: Configure dentry operations at dentry-creation time ext4: Configure dentry operations at dentry-creation time libfs: Add helper to choose dentry operations at mount-time libfs: Merge encrypted_ci_dentry_ops and ci_dentry_ops fscrypt: Drop d_revalidate once the key is added fscrypt: Drop d_revalidate for valid dentries during lookup fscrypt: Factor out a helper to configure the lookup dentry ovl: Always reject mounting over case-insensitive directories libfs: Attempt exact-match comparison first during casefolded lookup Signed-off-by: Christian Brauner <brauner@kernel.org>
2 parents 91e78a1 + 101c3fa commit 09406ad

File tree

11 files changed

+128
-86
lines changed

11 files changed

+128
-86
lines changed

fs/crypto/hooks.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,8 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
102102
if (err && err != -ENOENT)
103103
return err;
104104

105-
if (fname->is_nokey_name) {
106-
spin_lock(&dentry->d_lock);
107-
dentry->d_flags |= DCACHE_NOKEY_NAME;
108-
spin_unlock(&dentry->d_lock);
109-
}
105+
fscrypt_prepare_dentry(dentry, fname->is_nokey_name);
106+
110107
return err;
111108
}
112109
EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
@@ -131,12 +128,10 @@ EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
131128
int fscrypt_prepare_lookup_partial(struct inode *dir, struct dentry *dentry)
132129
{
133130
int err = fscrypt_get_encryption_info(dir, true);
131+
bool is_nokey_name = (!err && !fscrypt_has_encryption_key(dir));
132+
133+
fscrypt_prepare_dentry(dentry, is_nokey_name);
134134

135-
if (!err && !fscrypt_has_encryption_key(dir)) {
136-
spin_lock(&dentry->d_lock);
137-
dentry->d_flags |= DCACHE_NOKEY_NAME;
138-
spin_unlock(&dentry->d_lock);
139-
}
140135
return err;
141136
}
142137
EXPORT_SYMBOL_GPL(fscrypt_prepare_lookup_partial);

fs/ext4/namei.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1762,7 +1762,6 @@ static struct buffer_head *ext4_lookup_entry(struct inode *dir,
17621762
struct buffer_head *bh;
17631763

17641764
err = ext4_fname_prepare_lookup(dir, dentry, &fname);
1765-
generic_set_encrypted_ci_d_ops(dentry);
17661765
if (err == -ENOENT)
17671766
return NULL;
17681767
if (err)

fs/ext4/super.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5484,6 +5484,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
54845484
goto failed_mount4;
54855485
}
54865486

5487+
generic_set_sb_d_ops(sb);
54875488
sb->s_root = d_make_root(root);
54885489
if (!sb->s_root) {
54895490
ext4_msg(sb, KERN_ERR, "get root dentry failed");

fs/f2fs/namei.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,6 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
531531
}
532532

533533
err = f2fs_prepare_lookup(dir, dentry, &fname);
534-
generic_set_encrypted_ci_d_ops(dentry);
535534
if (err == -ENOENT)
536535
goto out_splice;
537536
if (err)

fs/f2fs/super.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4660,6 +4660,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
46604660
goto free_node_inode;
46614661
}
46624662

4663+
generic_set_sb_d_ops(sb);
46634664
sb->s_root = d_make_root(root); /* allocate root dentry */
46644665
if (!sb->s_root) {
46654666
err = -ENOMEM;

fs/libfs.c

Lines changed: 40 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,16 +1738,28 @@ bool is_empty_dir_inode(struct inode *inode)
17381738
static int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
17391739
const char *str, const struct qstr *name)
17401740
{
1741-
const struct dentry *parent = READ_ONCE(dentry->d_parent);
1742-
const struct inode *dir = READ_ONCE(parent->d_inode);
1743-
const struct super_block *sb = dentry->d_sb;
1744-
const struct unicode_map *um = sb->s_encoding;
1745-
struct qstr qstr = QSTR_INIT(str, len);
1741+
const struct dentry *parent;
1742+
const struct inode *dir;
17461743
char strbuf[DNAME_INLINE_LEN];
1747-
int ret;
1744+
struct qstr qstr;
1745+
1746+
/*
1747+
* Attempt a case-sensitive match first. It is cheaper and
1748+
* should cover most lookups, including all the sane
1749+
* applications that expect a case-sensitive filesystem.
1750+
*
1751+
* This comparison is safe under RCU because the caller
1752+
* guarantees the consistency between str and len. See
1753+
* __d_lookup_rcu_op_compare() for details.
1754+
*/
1755+
if (len == name->len && !memcmp(str, name->name, len))
1756+
return 0;
17481757

1758+
parent = READ_ONCE(dentry->d_parent);
1759+
dir = READ_ONCE(parent->d_inode);
17491760
if (!dir || !IS_CASEFOLDED(dir))
1750-
goto fallback;
1761+
return 1;
1762+
17511763
/*
17521764
* If the dentry name is stored in-line, then it may be concurrently
17531765
* modified by a rename. If this happens, the VFS will eventually retry
@@ -1758,20 +1770,14 @@ static int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
17581770
if (len <= DNAME_INLINE_LEN - 1) {
17591771
memcpy(strbuf, str, len);
17601772
strbuf[len] = 0;
1761-
qstr.name = strbuf;
1773+
str = strbuf;
17621774
/* prevent compiler from optimizing out the temporary buffer */
17631775
barrier();
17641776
}
1765-
ret = utf8_strncasecmp(um, name, &qstr);
1766-
if (ret >= 0)
1767-
return ret;
1777+
qstr.len = len;
1778+
qstr.name = str;
17681779

1769-
if (sb_has_strict_encoding(sb))
1770-
return -EINVAL;
1771-
fallback:
1772-
if (len != name->len)
1773-
return 1;
1774-
return !!memcmp(str, name->name, len);
1780+
return utf8_strncasecmp(dentry->d_sb->s_encoding, name, &qstr);
17751781
}
17761782

17771783
/**
@@ -1800,73 +1806,45 @@ static int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)
18001806
static const struct dentry_operations generic_ci_dentry_ops = {
18011807
.d_hash = generic_ci_d_hash,
18021808
.d_compare = generic_ci_d_compare,
1803-
};
1804-
#endif
1805-
18061809
#ifdef CONFIG_FS_ENCRYPTION
1807-
static const struct dentry_operations generic_encrypted_dentry_ops = {
18081810
.d_revalidate = fscrypt_d_revalidate,
1811+
#endif
18091812
};
18101813
#endif
18111814

1812-
#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
1813-
static const struct dentry_operations generic_encrypted_ci_dentry_ops = {
1814-
.d_hash = generic_ci_d_hash,
1815-
.d_compare = generic_ci_d_compare,
1815+
#ifdef CONFIG_FS_ENCRYPTION
1816+
static const struct dentry_operations generic_encrypted_dentry_ops = {
18161817
.d_revalidate = fscrypt_d_revalidate,
18171818
};
18181819
#endif
18191820

18201821
/**
1821-
* generic_set_encrypted_ci_d_ops - helper for setting d_ops for given dentry
1822-
* @dentry: dentry to set ops on
1823-
*
1824-
* Casefolded directories need d_hash and d_compare set, so that the dentries
1825-
* contained in them are handled case-insensitively. Note that these operations
1826-
* are needed on the parent directory rather than on the dentries in it, and
1827-
* while the casefolding flag can be toggled on and off on an empty directory,
1828-
* dentry_operations can't be changed later. As a result, if the filesystem has
1829-
* casefolding support enabled at all, we have to give all dentries the
1830-
* casefolding operations even if their inode doesn't have the casefolding flag
1831-
* currently (and thus the casefolding ops would be no-ops for now).
1832-
*
1833-
* Encryption works differently in that the only dentry operation it needs is
1834-
* d_revalidate, which it only needs on dentries that have the no-key name flag.
1835-
* The no-key flag can't be set "later", so we don't have to worry about that.
1822+
* generic_set_sb_d_ops - helper for choosing the set of
1823+
* filesystem-wide dentry operations for the enabled features
1824+
* @sb: superblock to be configured
18361825
*
1837-
* Finally, to maximize compatibility with overlayfs (which isn't compatible
1838-
* with certain dentry operations) and to avoid taking an unnecessary
1839-
* performance hit, we use custom dentry_operations for each possible
1840-
* combination rather than always installing all operations.
1826+
* Filesystems supporting casefolding and/or fscrypt can call this
1827+
* helper at mount-time to configure sb->s_d_op to best set of dentry
1828+
* operations required for the enabled features. The helper must be
1829+
* called after these have been configured, but before the root dentry
1830+
* is created.
18411831
*/
1842-
void generic_set_encrypted_ci_d_ops(struct dentry *dentry)
1832+
void generic_set_sb_d_ops(struct super_block *sb)
18431833
{
1844-
#ifdef CONFIG_FS_ENCRYPTION
1845-
bool needs_encrypt_ops = dentry->d_flags & DCACHE_NOKEY_NAME;
1846-
#endif
18471834
#if IS_ENABLED(CONFIG_UNICODE)
1848-
bool needs_ci_ops = dentry->d_sb->s_encoding;
1849-
#endif
1850-
#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
1851-
if (needs_encrypt_ops && needs_ci_ops) {
1852-
d_set_d_op(dentry, &generic_encrypted_ci_dentry_ops);
1835+
if (sb->s_encoding) {
1836+
sb->s_d_op = &generic_ci_dentry_ops;
18531837
return;
18541838
}
18551839
#endif
18561840
#ifdef CONFIG_FS_ENCRYPTION
1857-
if (needs_encrypt_ops) {
1858-
d_set_d_op(dentry, &generic_encrypted_dentry_ops);
1859-
return;
1860-
}
1861-
#endif
1862-
#if IS_ENABLED(CONFIG_UNICODE)
1863-
if (needs_ci_ops) {
1864-
d_set_d_op(dentry, &generic_ci_dentry_ops);
1841+
if (sb->s_cop) {
1842+
sb->s_d_op = &generic_encrypted_dentry_ops;
18651843
return;
18661844
}
18671845
#endif
18681846
}
1869-
EXPORT_SYMBOL(generic_set_encrypted_ci_d_ops);
1847+
EXPORT_SYMBOL(generic_set_sb_d_ops);
18701848

18711849
/**
18721850
* inode_maybe_inc_iversion - increments i_version

fs/overlayfs/params.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,20 @@ static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path,
280280
{
281281
struct ovl_fs_context *ctx = fc->fs_private;
282282

283-
if (ovl_dentry_weird(path->dentry))
284-
return invalfc(fc, "filesystem on %s not supported", name);
285-
286283
if (!d_is_dir(path->dentry))
287284
return invalfc(fc, "%s is not a directory", name);
288285

286+
/*
287+
* Root dentries of case-insensitive capable filesystems might
288+
* not have the dentry operations set, but still be incompatible
289+
* with overlayfs. Check explicitly to prevent post-mount
290+
* failures.
291+
*/
292+
if (sb_has_encoding(path->mnt->mnt_sb))
293+
return invalfc(fc, "case-insensitive capable filesystem on %s not supported", name);
294+
295+
if (ovl_dentry_weird(path->dentry))
296+
return invalfc(fc, "filesystem on %s not supported", name);
289297

290298
/*
291299
* Check whether upper path is read-only here to report failures

fs/ubifs/dir.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,6 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
205205
dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
206206

207207
err = fscrypt_prepare_lookup(dir, dentry, &nm);
208-
generic_set_encrypted_ci_d_ops(dentry);
209208
if (err == -ENOENT)
210209
return d_splice_alias(NULL, dentry);
211210
if (err)

fs/ubifs/super.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,6 +2239,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
22392239
goto out_umount;
22402240
}
22412241

2242+
generic_set_sb_d_ops(sb);
22422243
sb->s_root = d_make_root(root);
22432244
if (!sb->s_root) {
22442245
err = -ENOMEM;

include/linux/fs.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3310,7 +3310,16 @@ extern int generic_file_fsync(struct file *, loff_t, loff_t, int);
33103310

33113311
extern int generic_check_addressable(unsigned, u64);
33123312

3313-
extern void generic_set_encrypted_ci_d_ops(struct dentry *dentry);
3313+
extern void generic_set_sb_d_ops(struct super_block *sb);
3314+
3315+
static inline bool sb_has_encoding(const struct super_block *sb)
3316+
{
3317+
#if IS_ENABLED(CONFIG_UNICODE)
3318+
return !!sb->s_encoding;
3319+
#else
3320+
return false;
3321+
#endif
3322+
}
33143323

33153324
int may_setattr(struct mnt_idmap *idmap, struct inode *inode,
33163325
unsigned int ia_valid);

0 commit comments

Comments
 (0)