ANDROID: sync generic casefolding code with patches going upstream

Get the generic casefolding code in sync with the patches that are
queued in f2fs.git#dev for 5.10.

Equivalently, this reverts the patch
"ANDROID-fs-adjust-casefolding-support-to-match-android-mainline.patch"
from the android-mainline quilt series, with the following conflicts:

Conflicts:
	fs/ext4/hash.c  # due to "ANDROID: ext4: Handle casefolding with encryption"
	fs/ext4/namei.c # due to "ANDROID: ext4: Handle casefolding with encryption"
	fs/f2fs/dir.c   # due to "ANDROID: f2fs: Handle casefolding with Encryption"

Bug: 161184936
Cc: Daniel Rosenberg <drosen@google.com>
Cc: Paul Lawrence <paullawrence@google.com>
Cc: Jaegeuk Kim <jaegeuk@google.com>
Change-Id: I0ae169f0f5f413fb21e4be7a163213aef3fa6756
Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
Eric Biggers 2020-09-21 16:10:07 -07:00 committed by Alistair Delva
parent fb3b36d52f
commit 76bfcb2dc2
6 changed files with 45 additions and 40 deletions

View File

@ -296,7 +296,7 @@ int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
unsigned char *buff;
struct qstr qstr = {.name = name, .len = len };
if (len && needs_casefold(dir) && um) {
if (len && IS_CASEFOLDED(dir) && um) {
buff = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL);
if (!buff)
return -ENOMEM;

View File

@ -1359,7 +1359,7 @@ static int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
/* Handle invalid character sequence as either an error
* or as an opaque byte sequence.
*/
if (sb_has_enc_strict_mode(sb))
if (sb_has_strict_encoding(sb))
ret = -EINVAL;
else if (name->len != entry.len)
ret = 1;
@ -1378,7 +1378,7 @@ int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
struct dx_hash_info *hinfo = &name->hinfo;
int len;
if (!needs_casefold(dir)) {
if (!IS_CASEFOLDED(dir) || !dir->i_sb->s_encoding) {
cf_name->name = NULL;
return 0;
}
@ -1429,7 +1429,7 @@ static bool ext4_match(struct inode *parent,
#endif
#ifdef CONFIG_UNICODE
if (needs_casefold(parent)) {
if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent)) {
if (fname->cf_name.name) {
struct qstr cf = {.name = fname->cf_name.name,
.len = fname->cf_name.len};
@ -2302,7 +2302,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
return -EINVAL;
#ifdef CONFIG_UNICODE
if (sb_has_enc_strict_mode(sb) && IS_CASEFOLDED(dir) &&
if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) &&
sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name))
return -EINVAL;
#endif

View File

@ -76,21 +76,22 @@ int f2fs_init_casefolded_name(const struct inode *dir,
struct f2fs_filename *fname)
{
#ifdef CONFIG_UNICODE
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
struct super_block *sb = dir->i_sb;
struct f2fs_sb_info *sbi = F2FS_SB(sb);
if (IS_CASEFOLDED(dir)) {
fname->cf_name.name = f2fs_kmalloc(sbi, F2FS_NAME_LEN,
GFP_NOFS);
if (!fname->cf_name.name)
return -ENOMEM;
fname->cf_name.len = utf8_casefold(sbi->sb->s_encoding,
fname->cf_name.len = utf8_casefold(sb->s_encoding,
fname->usr_fname,
fname->cf_name.name,
F2FS_NAME_LEN);
if ((int)fname->cf_name.len <= 0) {
kfree(fname->cf_name.name);
fname->cf_name.name = NULL;
if (sb_has_enc_strict_mode(dir->i_sb))
if (sb_has_strict_encoding(sb))
return -EINVAL;
/* fall back to treating name as opaque byte sequence */
}
@ -246,7 +247,7 @@ static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
* In strict mode, ignore invalid names. In non-strict mode,
* fall back to treating them as opaque byte sequences.
*/
if (sb_has_enc_strict_mode(sb) || name->len != entry.len)
if (sb_has_strict_encoding(sb) || name->len != entry.len)
res = 1;
else
res = memcmp(name->name, entry.name, name->len);

View File

@ -1367,27 +1367,38 @@ bool is_empty_dir_inode(struct inode *inode)
}
#ifdef CONFIG_UNICODE
bool needs_casefold(const struct inode *dir)
/*
* Determine if the name of a dentry should be casefolded.
*
* Return: if names will need casefolding
*/
static bool needs_casefold(const struct inode *dir)
{
return IS_CASEFOLDED(dir) && dir->i_sb->s_encoding &&
(!IS_ENCRYPTED(dir) || fscrypt_has_encryption_key(dir));
return IS_CASEFOLDED(dir) && dir->i_sb->s_encoding;
}
EXPORT_SYMBOL(needs_casefold);
/**
* generic_ci_d_compare - generic d_compare implementation for casefolding filesystems
* @dentry: dentry whose name we are checking against
* @len: len of name of dentry
* @str: str pointer to name of dentry
* @name: Name to compare against
*
* Return: 0 if names match, 1 if mismatch, or -ERRNO
*/
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 *inode = READ_ONCE(parent->d_inode);
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 entry = QSTR_INIT(str, len);
struct qstr qstr = QSTR_INIT(str, len);
char strbuf[DNAME_INLINE_LEN];
int ret;
if (!inode || !needs_casefold(inode))
if (!dir || !needs_casefold(dir))
goto fallback;
/*
* 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
@ -1398,16 +1409,15 @@ 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;
entry.name = strbuf;
qstr.name = strbuf;
/* prevent compiler from optimizing out the temporary buffer */
barrier();
}
ret = utf8_strncasecmp(um, name, &entry);
ret = utf8_strncasecmp(um, name, &qstr);
if (ret >= 0)
return ret;
if (sb_has_enc_strict_mode(sb))
if (sb_has_strict_encoding(sb))
return -EINVAL;
fallback:
if (len != name->len)
@ -1416,27 +1426,27 @@ int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
}
EXPORT_SYMBOL(generic_ci_d_compare);
/**
* generic_ci_d_hash - generic d_hash implementation for casefolding filesystems
* @dentry: dentry of the parent directory
* @str: qstr of name whose hash we should fill in
*
* Return: 0 if hash was successful or unchanged, and -EINVAL on error
*/
int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)
{
const struct inode *inode = READ_ONCE(dentry->d_inode);
const struct inode *dir = READ_ONCE(dentry->d_inode);
struct super_block *sb = dentry->d_sb;
const struct unicode_map *um = sb->s_encoding;
int ret = 0;
if (!inode || !needs_casefold(inode))
if (!dir || !needs_casefold(dir))
return 0;
ret = utf8_casefold_hash(um, dentry, str);
if (ret < 0)
goto err;
if (ret < 0 && sb_has_strict_encoding(sb))
return -EINVAL;
return 0;
err:
if (sb_has_enc_strict_mode(sb))
ret = -EINVAL;
else
ret = 0;
return ret;
}
EXPORT_SYMBOL(generic_ci_d_hash);

View File

@ -138,7 +138,7 @@ int utf8_casefold_hash(const struct unicode_map *um, const void *salt,
while ((c = utf8byte(&cur))) {
if (c < 0)
return c;
return -EINVAL;
hash = partial_name_hash((unsigned char)c, hash);
}
str->hash = end_name_hash(hash);

View File

@ -1374,7 +1374,7 @@ extern int send_sigurg(struct fown_struct *fown);
/* These flags relate to encoding and casefolding */
#define SB_ENC_STRICT_MODE_FL (1 << 0)
#define sb_has_enc_strict_mode(sb) \
#define sb_has_strict_encoding(sb) \
(sb->s_encoding_flags & SB_ENC_STRICT_MODE_FL)
/*
@ -3276,12 +3276,6 @@ extern int generic_check_addressable(unsigned, u64);
extern int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str);
extern int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
const char *str, const struct qstr *name);
extern bool needs_casefold(const struct inode *dir);
#else
static inline bool needs_casefold(const struct inode *dir)
{
return 0;
}
#endif
extern void generic_set_encrypted_ci_d_ops(struct inode *dir,
struct dentry *dentry);