From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.2 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, URIBL_DBL_ABUSE_MALW,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C62D1C33CB2 for ; Tue, 28 Jan 2020 23:04:57 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 923972087F for ; Tue, 28 Jan 2020 23:04:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="YFihfNX4"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="AoFeMGTR" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 923972087F Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mtd-bounces+linux-mtd=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:To:From:Subject:References:Mime-Version :Message-Id:In-Reply-To:Date:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=PF3M4PlnR+TTy4EokCe1zBAPyZQNaNUSBbmfBP9w2hg=; b=YFihfNX4Jh18AY Givf+Qx/wSYN+Gg2WNYe4Il7hhEaHmTxEAIDq3chfJGef/QaLar05rF2w85yxpLjqRoiKH0UeLCOH xC5wZ9aSkNtEj6iTHocW14m54Lyz/m993OurEHP6F4Y2SsO5yQhtuTazhRBYhRZ3xqts2ARrqxa5V p+ihFwuAcn/hBf5fHsuK9PyCBD2Pr99doSwi6so/eiEsyRsCqI4v3leoryE+M13INJTz3kStbN7Lr MqszZOj542UjvMGfb2BBsK5seGpSp4ORJx73pjzRm/bk/YmxiARQL0pnwPDbvYTAdKN/tlw2uLjQ8 SLXcRLtpOWo5Gwk4Nzow==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1iwZuR-0003Ck-QZ; Tue, 28 Jan 2020 23:04:39 +0000 Received: from mail-pj1-x1049.google.com ([2607:f8b0:4864:20::1049]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1iwZuD-0002zL-K4 for linux-mtd@lists.infradead.org; Tue, 28 Jan 2020 23:04:27 +0000 Received: by mail-pj1-x1049.google.com with SMTP id u10so2301741pjy.2 for ; Tue, 28 Jan 2020 15:04:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=pINL0HO+nJObZ5TbcW6esU1PR8RvkfGKC5Yq2whqHX0=; b=AoFeMGTRwbbGCx6v824jnS6htYaziypb1tNQAiqBtoVTlaZleykYenVrP2JnDfuVcY OxG5//g6Wl4Kq9uJ8mfxdTDF7gZw0Bh5yAJxtRCL0Y69Z4y8z4BAhi7WwJXh0u/cfgWc deHWpDZ4UuAKD+MHgGUKxSaB8CvoRnPHoW8BqeS4j9a6RpYtsl198u6RJ+kTQ7T77mWI 6ZxhyNP/glTPR66QRsTwhIxJ55PXGKEzEXXVno93O/wsznFs5W30mbRc7ovBO82L9TeV PURODZtKNm89Ml+io61tluZ1FJsirLE5SIhHUtA6Ob3rl8lyNDzoqMFbNmrBNHrO4sph ckag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=pINL0HO+nJObZ5TbcW6esU1PR8RvkfGKC5Yq2whqHX0=; b=tkXYgnyMY4JBVY4vwIi5RIPkJmsHNOohezCddAs0E9VHv+7t2oepZOtA+EpDfVBE5b 2O0//DDuXuACpqm0wSH87g19Axos22BvKbWyPFdsbVpczsRUAp6IAglVy+ePqVNlLzbv zkJRMSfCeTBY1oM3X4NytJ6NJg1BtoJ3iqHUcxppk7BxMupJ93X/9vZPramdg1YSUjBx w6kAtLtKhqnMaODBjwx85Unsx1xvaMmNETwPS2gWm29EfPqsUnXFy5n6PqpOOvhLBAzw jB7+n0WgvTwkePep8ac/SckcSME0LVHZOvzMkBsNuVn2qLna9kZKSHEyu+/qKZOJhYPg EcoQ== X-Gm-Message-State: APjAAAX8L3NuxR++/kMSc4fhtOjBdUOmN+IF08pV3EQUFMHCRJIKp8LR Cc+LLM5FIhfUxLbmI/WpbJ/A1F2cJdU= X-Google-Smtp-Source: APXvYqy11+dEOxjeLTisd07FIsi9hsfyVDU5TNEnzu/Q8nsPbrsCCHLzlAbYRru0TQSFm5eepDrXW32qe1M= X-Received: by 2002:a63:313:: with SMTP id 19mr26848366pgd.7.1580252664382; Tue, 28 Jan 2020 15:04:24 -0800 (PST) Date: Tue, 28 Jan 2020 15:03:24 -0800 In-Reply-To: <20200128230328.183524-1-drosen@google.com> Message-Id: <20200128230328.183524-2-drosen@google.com> Mime-Version: 1.0 References: <20200128230328.183524-1-drosen@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v6 1/5] unicode: Add standard casefolded d_ops From: Daniel Rosenberg To: "Theodore Ts'o" , linux-ext4@vger.kernel.org, Jaegeuk Kim , Chao Yu , linux-f2fs-devel@lists.sourceforge.net, Eric Biggers , linux-fscrypt@vger.kernel.org, Alexander Viro , Richard Weinberger X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200128_150425_661383_CA13D0AB X-CRM114-Status: GOOD ( 18.20 ) X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Daniel Rosenberg , linux-doc@vger.kernel.org, kernel-team@android.com, Jonathan Corbet , linux-kernel@vger.kernel.org, Andreas Dilger , linux-fsdevel@vger.kernel.org, linux-mtd@lists.infradead.org, Gabriel Krisman Bertazi Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-mtd" Errors-To: linux-mtd-bounces+linux-mtd=archiver.kernel.org@lists.infradead.org This adds dentry_operations implementations for d_hash and d_compare which can be used by any filesystem using utf8 casefolding, unifying the existing ext4 and f2fs functions. In order to do this, we add new variables to struct super_block and switch ext4 and f2fs over to those instead of maintaining their own versions. Signed-off-by: Daniel Rosenberg --- fs/ext4/dir.c | 45 ++---------------------------- fs/ext4/ext4.h | 4 --- fs/ext4/hash.c | 2 +- fs/ext4/namei.c | 20 ++++++-------- fs/ext4/super.c | 10 +++---- fs/f2fs/dir.c | 60 +++++++--------------------------------- fs/f2fs/f2fs.h | 4 --- fs/f2fs/hash.c | 2 +- fs/f2fs/super.c | 10 +++---- fs/f2fs/sysfs.c | 8 +++--- fs/unicode/utf8-core.c | 61 +++++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 10 +++++++ include/linux/unicode.h | 17 ++++++++++++ 13 files changed, 124 insertions(+), 129 deletions(-) diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 4e093277c8bfb..e9f7c32089dfc 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -668,49 +668,8 @@ const struct file_operations ext4_dir_operations = { }; #ifdef CONFIG_UNICODE -static int ext4_d_compare(const struct dentry *dentry, unsigned int len, - const char *str, const struct qstr *name) -{ - struct qstr qstr = {.name = str, .len = len }; - struct inode *inode = dentry->d_parent->d_inode; - - if (!IS_CASEFOLDED(inode) || !EXT4_SB(inode->i_sb)->s_encoding) { - if (len != name->len) - return -1; - return memcmp(str, name->name, len); - } - - return ext4_ci_compare(inode, name, &qstr, false); -} - -static int ext4_d_hash(const struct dentry *dentry, struct qstr *str) -{ - const struct ext4_sb_info *sbi = EXT4_SB(dentry->d_sb); - const struct unicode_map *um = sbi->s_encoding; - unsigned char *norm; - int len, ret = 0; - - if (!IS_CASEFOLDED(dentry->d_inode) || !um) - return 0; - - norm = kmalloc(PATH_MAX, GFP_ATOMIC); - if (!norm) - return -ENOMEM; - - len = utf8_casefold(um, str, norm, PATH_MAX); - if (len < 0) { - if (ext4_has_strict_mode(sbi)) - ret = -EINVAL; - goto out; - } - str->hash = full_name_hash(dentry, norm, len); -out: - kfree(norm); - return ret; -} - const struct dentry_operations ext4_dentry_ops = { - .d_hash = ext4_d_hash, - .d_compare = ext4_d_compare, + .d_hash = utf8_ci_d_hash, + .d_compare = utf8_ci_d_compare, }; #endif diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index f8578caba40d5..3162ef2e53d46 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1430,10 +1430,6 @@ struct ext4_sb_info { struct kobject s_kobj; struct completion s_kobj_unregister; struct super_block *s_sb; -#ifdef CONFIG_UNICODE - struct unicode_map *s_encoding; - __u16 s_encoding_flags; -#endif /* Journaling */ struct journal_s *s_journal; diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index 3e133793a5a34..143b0073b3f46 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c @@ -275,7 +275,7 @@ int ext4fs_dirhash(const struct inode *dir, const char *name, int len, struct dx_hash_info *hinfo) { #ifdef CONFIG_UNICODE - const struct unicode_map *um = EXT4_SB(dir->i_sb)->s_encoding; + const struct unicode_map *um = dir->i_sb->s_encoding; int r, dlen; unsigned char *buff; struct qstr qstr = {.name = name, .len = len }; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 1cb42d9407847..7f4e625ab2f9b 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1282,8 +1282,8 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block) int ext4_ci_compare(const struct inode *parent, const struct qstr *name, const struct qstr *entry, bool quick) { - const struct ext4_sb_info *sbi = EXT4_SB(parent->i_sb); - const struct unicode_map *um = sbi->s_encoding; + const struct super_block *sb = parent->i_sb; + const struct unicode_map *um = sb->s_encoding; int ret; if (quick) @@ -1295,7 +1295,7 @@ 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 (ext4_has_strict_mode(sbi)) + if (sb_has_enc_strict_mode(sb)) return -EINVAL; if (name->len != entry->len) @@ -1312,7 +1312,7 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname, { int len; - if (!IS_CASEFOLDED(dir) || !EXT4_SB(dir->i_sb)->s_encoding) { + if (!needs_casefold(dir)) { cf_name->name = NULL; return; } @@ -1321,7 +1321,7 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname, if (!cf_name->name) return; - len = utf8_casefold(EXT4_SB(dir->i_sb)->s_encoding, + len = utf8_casefold(dir->i_sb->s_encoding, iname, cf_name->name, EXT4_NAME_LEN); if (len <= 0) { @@ -1358,7 +1358,7 @@ static inline bool ext4_match(const struct inode *parent, #endif #ifdef CONFIG_UNICODE - if (EXT4_SB(parent->i_sb)->s_encoding && IS_CASEFOLDED(parent)) { + if (needs_casefold(parent)) { if (fname->cf_name.name) { struct qstr cf = {.name = fname->cf_name.name, .len = fname->cf_name.len}; @@ -2164,9 +2164,6 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, struct buffer_head *bh = NULL; struct ext4_dir_entry_2 *de; struct super_block *sb; -#ifdef CONFIG_UNICODE - struct ext4_sb_info *sbi; -#endif struct ext4_filename fname; int retval; int dx_fallback=0; @@ -2183,9 +2180,8 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, return -EINVAL; #ifdef CONFIG_UNICODE - sbi = EXT4_SB(sb); - if (ext4_has_strict_mode(sbi) && IS_CASEFOLDED(dir) && - sbi->s_encoding && utf8_validate(sbi->s_encoding, &dentry->d_name)) + if (sb_has_enc_strict_mode(sb) && IS_CASEFOLDED(dir) && + sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name)) return -EINVAL; #endif diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 2937a8873fe13..b7e9f0310ec23 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1056,7 +1056,7 @@ static void ext4_put_super(struct super_block *sb) kfree(sbi->s_blockgroup_lock); fs_put_dax(sbi->s_daxdev); #ifdef CONFIG_UNICODE - utf8_unload(sbi->s_encoding); + utf8_unload(sb->s_encoding); #endif kfree(sbi); } @@ -3850,7 +3850,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount; #ifdef CONFIG_UNICODE - if (ext4_has_feature_casefold(sb) && !sbi->s_encoding) { + if (ext4_has_feature_casefold(sb) && !sb->s_encoding) { const struct ext4_sb_encodings *encoding_info; struct unicode_map *encoding; __u16 encoding_flags; @@ -3881,8 +3881,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) "%s-%s with flags 0x%hx", encoding_info->name, encoding_info->version?:"\b", encoding_flags); - sbi->s_encoding = encoding; - sbi->s_encoding_flags = encoding_flags; + sb->s_encoding = encoding; + sb->s_encoding_flags = encoding_flags; } #endif @@ -4684,7 +4684,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) crypto_free_shash(sbi->s_chksum_driver); #ifdef CONFIG_UNICODE - utf8_unload(sbi->s_encoding); + utf8_unload(sb->s_encoding); #endif #ifdef CONFIG_QUOTA diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index d9ad842945df5..a1dd9939e20bf 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -114,8 +114,8 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir, int f2fs_ci_compare(const struct inode *parent, const struct qstr *name, const struct qstr *entry, bool quick) { - const struct f2fs_sb_info *sbi = F2FS_SB(parent->i_sb); - const struct unicode_map *um = sbi->s_encoding; + const struct super_block *sb = parent->i_sb; + const struct unicode_map *um = sb->s_encoding; int ret; if (quick) @@ -127,7 +127,7 @@ int f2fs_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 (f2fs_has_strict_mode(sbi)) + if (sb_has_enc_strict_mode(sb)) return -EINVAL; if (name->len != entry->len) @@ -154,7 +154,7 @@ static void f2fs_fname_setup_ci_filename(struct inode *dir, if (!cf_name->name) return; - cf_name->len = utf8_casefold(sbi->s_encoding, + cf_name->len = utf8_casefold(dir->i_sb->s_encoding, iname, cf_name->name, F2FS_NAME_LEN); if ((int)cf_name->len <= 0) { @@ -173,7 +173,7 @@ static inline bool f2fs_match_name(struct f2fs_dentry_ptr *d, { #ifdef CONFIG_UNICODE struct inode *parent = d->inode; - struct f2fs_sb_info *sbi = F2FS_I_SB(parent); + struct super_block *sb = parent->i_sb; struct qstr entry; #endif @@ -184,7 +184,7 @@ static inline bool f2fs_match_name(struct f2fs_dentry_ptr *d, entry.name = d->filename[bit_pos]; entry.len = de->name_len; - if (sbi->s_encoding && IS_CASEFOLDED(parent)) { + if (sb->s_encoding && IS_CASEFOLDED(parent)) { if (cf_str->name) { struct qstr cf = {.name = cf_str->name, .len = cf_str->len}; @@ -357,8 +357,8 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, int err; #ifdef CONFIG_UNICODE - if (f2fs_has_strict_mode(F2FS_I_SB(dir)) && IS_CASEFOLDED(dir) && - utf8_validate(F2FS_I_SB(dir)->s_encoding, child)) { + if (sb_has_enc_strict_mode(dir->i_sb) && IS_CASEFOLDED(dir) && + utf8_validate(dir->i_sb->s_encoding, child)) { *res_page = ERR_PTR(-EINVAL); return NULL; } @@ -1065,48 +1065,8 @@ const struct file_operations f2fs_dir_operations = { }; #ifdef CONFIG_UNICODE -static int f2fs_d_compare(const struct dentry *dentry, unsigned int len, - const char *str, const struct qstr *name) -{ - struct qstr qstr = {.name = str, .len = len }; - - if (!IS_CASEFOLDED(dentry->d_parent->d_inode)) { - if (len != name->len) - return -1; - return memcmp(str, name, len); - } - - return f2fs_ci_compare(dentry->d_parent->d_inode, name, &qstr, false); -} - -static int f2fs_d_hash(const struct dentry *dentry, struct qstr *str) -{ - struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); - const struct unicode_map *um = sbi->s_encoding; - unsigned char *norm; - int len, ret = 0; - - if (!IS_CASEFOLDED(dentry->d_inode)) - return 0; - - norm = f2fs_kmalloc(sbi, PATH_MAX, GFP_ATOMIC); - if (!norm) - return -ENOMEM; - - len = utf8_casefold(um, str, norm, PATH_MAX); - if (len < 0) { - if (f2fs_has_strict_mode(sbi)) - ret = -EINVAL; - goto out; - } - str->hash = full_name_hash(dentry, norm, len); -out: - kvfree(norm); - return ret; -} - const struct dentry_operations f2fs_dentry_ops = { - .d_hash = f2fs_d_hash, - .d_compare = f2fs_d_compare, + .d_hash = utf8_ci_d_hash, + .d_compare = utf8_ci_d_compare, }; #endif diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 5a888a063c7f1..9f302de477022 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1184,10 +1184,6 @@ struct f2fs_sb_info { int valid_super_block; /* valid super block no */ unsigned long s_flag; /* flags for sbi */ struct mutex writepages; /* mutex for writepages() */ -#ifdef CONFIG_UNICODE - struct unicode_map *s_encoding; - __u16 s_encoding_flags; -#endif #ifdef CONFIG_BLK_DEV_ZONED unsigned int blocks_per_blkz; /* F2FS blocks per zone */ diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c index 5bc4dcd8fc03f..28acb24e7a7a8 100644 --- a/fs/f2fs/hash.c +++ b/fs/f2fs/hash.c @@ -110,7 +110,7 @@ f2fs_hash_t f2fs_dentry_hash(const struct inode *dir, { #ifdef CONFIG_UNICODE struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); - const struct unicode_map *um = sbi->s_encoding; + const struct unicode_map *um = dir->i_sb->s_encoding; int r, dlen; unsigned char *buff; struct qstr folded; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 5111e1ffe58ab..5de587f20ed35 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1144,7 +1144,7 @@ static void f2fs_put_super(struct super_block *sb) for (i = 0; i < NR_PAGE_TYPE; i++) kvfree(sbi->write_io[i]); #ifdef CONFIG_UNICODE - utf8_unload(sbi->s_encoding); + utf8_unload(sb->s_encoding); #endif kvfree(sbi); } @@ -3136,7 +3136,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) static int f2fs_setup_casefold(struct f2fs_sb_info *sbi) { #ifdef CONFIG_UNICODE - if (f2fs_sb_has_casefold(sbi) && !sbi->s_encoding) { + if (f2fs_sb_has_casefold(sbi) && !sbi->sb->s_encoding) { const struct f2fs_sb_encodings *encoding_info; struct unicode_map *encoding; __u16 encoding_flags; @@ -3167,8 +3167,8 @@ static int f2fs_setup_casefold(struct f2fs_sb_info *sbi) "%s-%s with flags 0x%hx", encoding_info->name, encoding_info->version?:"\b", encoding_flags); - sbi->s_encoding = encoding; - sbi->s_encoding_flags = encoding_flags; + sbi->sb->s_encoding = encoding; + sbi->sb->s_encoding_flags = encoding_flags; sbi->sb->s_d_op = &f2fs_dentry_ops; } #else @@ -3637,7 +3637,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) kvfree(sbi->write_io[i]); #ifdef CONFIG_UNICODE - utf8_unload(sbi->s_encoding); + utf8_unload(sb->s_encoding); #endif free_options: #ifdef CONFIG_QUOTA diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 70945ceb9c0ca..7fd37c8c9733a 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -88,10 +88,10 @@ static ssize_t encoding_show(struct f2fs_attr *a, #ifdef CONFIG_UNICODE if (f2fs_sb_has_casefold(sbi)) return snprintf(buf, PAGE_SIZE, "%s (%d.%d.%d)\n", - sbi->s_encoding->charset, - (sbi->s_encoding->version >> 16) & 0xff, - (sbi->s_encoding->version >> 8) & 0xff, - sbi->s_encoding->version & 0xff); + sbi->sb->s_encoding->charset, + (sbi->sb->s_encoding->version >> 16) & 0xff, + (sbi->sb->s_encoding->version >> 8) & 0xff, + sbi->sb->s_encoding->version & 0xff); #endif return snprintf(buf, PAGE_SIZE, "(none)"); } diff --git a/fs/unicode/utf8-core.c b/fs/unicode/utf8-core.c index 2a878b739115d..129a9e3fa91a4 100644 --- a/fs/unicode/utf8-core.c +++ b/fs/unicode/utf8-core.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "utf8n.h" @@ -212,4 +213,64 @@ void utf8_unload(struct unicode_map *um) } EXPORT_SYMBOL(utf8_unload); +int utf8_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 super_block *sb = dentry->d_sb; + const struct unicode_map *um = sb->s_encoding; + struct qstr entry = QSTR_INIT(str, len); + int ret; + + if (!inode || !needs_casefold(inode)) + goto fallback; + + ret = utf8_strncasecmp(um, name, &entry); + if (ret >= 0) + return ret; + + if (sb_has_enc_strict_mode(sb)) + return -EINVAL; +fallback: + if (len != name->len) + return 1; + return !!memcmp(str, name->name, len); +} +EXPORT_SYMBOL(utf8_ci_d_compare); + +int utf8_ci_d_hash(const struct dentry *dentry, struct qstr *str) +{ + const struct inode *inode = READ_ONCE(dentry->d_inode); + struct super_block *sb = dentry->d_sb; + const struct unicode_map *um = sb->s_encoding; + int ret = 0; + unsigned long hash; + const struct utf8data *data; + struct utf8cursor cur; + int c; + + if (!inode || !needs_casefold(inode)) + return 0; + + hash = init_name_hash(dentry); + data = utf8nfdicf(um->version); + if (utf8ncursor(&cur, data, str->name, str->len) < 0) + goto err; + + while ((c = utf8byte(&cur))) { + if (c < 0) + goto err; + hash = partial_name_hash((unsigned char)c, hash); + } + + str->hash = end_name_hash(hash); + return 0; +err: + if (sb_has_enc_strict_mode(sb)) + ret = -EINVAL; + return ret; +} +EXPORT_SYMBOL(utf8_ci_d_hash); + MODULE_LICENSE("GPL v2"); diff --git a/include/linux/fs.h b/include/linux/fs.h index 98e0349adb526..9a7092449e94f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1382,6 +1382,12 @@ extern int send_sigurg(struct fown_struct *fown); #define SB_ACTIVE (1<<30) #define SB_NOUSER (1<<31) +/* These flags relate to encoding and casefolding */ +#define SB_ENC_STRICT_MODE_FL (1 << 0) + +#define sb_has_enc_strict_mode(sb) \ + (sb->s_encoding_flags & SB_ENC_STRICT_MODE_FL) + /* * Umount options */ @@ -1449,6 +1455,10 @@ struct super_block { #endif #ifdef CONFIG_FS_VERITY const struct fsverity_operations *s_vop; +#endif +#ifdef CONFIG_UNICODE + struct unicode_map *s_encoding; + __u16 s_encoding_flags; #endif struct hlist_bl_head s_roots; /* alternate root dentries for NFS */ struct list_head s_mounts; /* list of mounts; _not_ for fs use */ diff --git a/include/linux/unicode.h b/include/linux/unicode.h index 990aa97d80496..5de313abeaf98 100644 --- a/include/linux/unicode.h +++ b/include/linux/unicode.h @@ -4,6 +4,8 @@ #include #include +#include +#include struct unicode_map { const char *charset; @@ -30,4 +32,19 @@ int utf8_casefold(const struct unicode_map *um, const struct qstr *str, struct unicode_map *utf8_load(const char *version); void utf8_unload(struct unicode_map *um); +int utf8_ci_d_hash(const struct dentry *dentry, struct qstr *str); +int utf8_ci_d_compare(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name); +#ifdef CONFIG_UNICODE +static inline bool needs_casefold(const struct inode *dir) +{ + return IS_CASEFOLDED(dir) && dir->i_sb->s_encoding && + (!IS_ENCRYPTED(dir) || fscrypt_has_encryption_key(dir)); +} +#else +static inline bool needs_casefold(const struct inode *dir) +{ + return 0; +} +#endif #endif /* _LINUX_UNICODE_H */ -- 2.25.0.341.g760bfbb309-goog ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/