Received: by 2002:a05:6902:102b:0:0:0:0 with SMTP id x11csp291320ybt; Tue, 23 Jun 2020 22:34:18 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxZ9+L4TInHOrESybEIVLi29l028VkZ0+7bOLlZJaQYD1paUsjakjnGAZQsABEe7a5RT9uU X-Received: by 2002:aa7:c0c7:: with SMTP id j7mr24492174edp.242.1592976857821; Tue, 23 Jun 2020 22:34:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1592976857; cv=none; d=google.com; s=arc-20160816; b=VEpW3Clxu5cPJzi9DdOY1EbmcTeSyvmjHKQ8PeSU3EEIzLz5aFJvUhFAplcw+R2Um3 JSXCkfka+G1drGos85J8xJflNl8BAirdv60X3FSnVifP865ZEc1offZdcE3pk27Gkg+v i5v2Nz8+MTmYjZKDq9b5w9XP0SVHHArqMhYTz1/2AkYG2nq97bPapOPhnSITH8Ne8h8k xZJbSCNAnnYli7oC7t0w+J06r2gFITHapv++IEqQxepJslUIHYIppavAodSNQP9uUxMP SuaabmxUxeg8WRrRazGMppAPk4s/bDz6ETbUX+Ps8WdgSyFF6CWs8lHJcaxliFF7N1rU 1fug== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:message-id :in-reply-to:date:references:organization:subject:cc:to:from; bh=8OduFUiTO3R2ov5W1O+gB1wqF3ds2aLKvhHc24yLMF4=; b=uLMHzECN8ylYFYEE4JKOXGUzz6UI/yDP6vr2bl0jSQuV0xq0Tlu83SxaVBilVglRfz B5xN4U5RtdtAhZNctNZf5fKLwwlFSwcTT3cuQ0cb0y2xFLYt3DK7jfxet71bKXqGSdVq C6YDa3vljyqr6bAUe+xXEKncVkSwf4DtT7sepv4lfVxcFoX5YMVj6VWHCvvANPgci340 550VBEziJlI96mgx4ZbDs6/M8T6R29K4ncYM1SdtCtda4OfABPeFBawGDZpuhKpIazqF QQyYKqYCY85GPHFuT9DcsPMqRCkz0wbc6zeuFTzUE5rBBNbZA7bqGpPUC1RUMpZrFyRb Ze6Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id s23si12221993ejq.306.2020.06.23.22.33.54; Tue, 23 Jun 2020 22:34:17 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388934AbgFXFdm (ORCPT + 99 others); Wed, 24 Jun 2020 01:33:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52736 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388470AbgFXFdm (ORCPT ); Wed, 24 Jun 2020 01:33:42 -0400 Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D10DFC061573; Tue, 23 Jun 2020 22:33:41 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: krisman) with ESMTPSA id B24E02A384C From: Gabriel Krisman Bertazi To: Daniel Rosenberg Cc: "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 , linux-mtd@lists.infradead.org, Andreas Dilger , Jonathan Corbet , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, kernel-team@android.com Subject: Re: [PATCH v9 2/4] fs: Add standard casefolding support Organization: Collabora References: <20200624043341.33364-1-drosen@google.com> <20200624043341.33364-3-drosen@google.com> Date: Wed, 24 Jun 2020 01:33:36 -0400 In-Reply-To: <20200624043341.33364-3-drosen@google.com> (Daniel Rosenberg's message of "Tue, 23 Jun 2020 21:33:39 -0700") Message-ID: <87bll9gh8v.fsf@collabora.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Daniel Rosenberg writes: > This adds general supporting functions for filesystems that use > utf8 casefolding. It provides standard dentry_operations and adds the > necessary structures in struct super_block to allow this standardization. > > Ext4 and F2fs will switch to these common implementations. > > Signed-off-by: Daniel Rosenberg > --- > fs/libfs.c | 101 +++++++++++++++++++++++++++++++++++++++++++++ > include/linux/fs.h | 22 ++++++++++ > 2 files changed, 123 insertions(+) > > diff --git a/fs/libfs.c b/fs/libfs.c > index 4d08edf19c782..f7345a5ed562f 100644 > --- a/fs/libfs.c > +++ b/fs/libfs.c > @@ -20,6 +20,8 @@ > #include > #include > #include > +#include > +#include > > #include > > @@ -1363,3 +1365,102 @@ bool is_empty_dir_inode(struct inode *inode) > return (inode->i_fop == &empty_dir_operations) && > (inode->i_op == &empty_dir_inode_operations); > } > + > +#ifdef CONFIG_UNICODE > +/** > + * needs_casefold - generic helper to determine if a filename should be casefolded > + * @dir: Parent directory > + * > + * Generic helper for filesystems to use to determine if the name of a dentry > + * should be casefolded. It does not make sense to casefold the no-key token of > + * an encrypted filename. > + * > + * Return: if names will need casefolding > + */ > +bool needs_casefold(const struct inode *dir) > +{ > + return IS_CASEFOLDED(dir) && dir->i_sb->s_encoding && > + (!IS_ENCRYPTED(dir) || fscrypt_has_encryption_key(dir)); > +} > +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 super_block *sb = dentry->d_sb; > + const struct unicode_map *um = sb->s_encoding; > + struct qstr qstr = QSTR_INIT(str, len); > + char strbuf[DNAME_INLINE_LEN]; > + int ret; > + > + if (!inode || !needs_casefold(inode)) > + 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 > + * 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. > + */ > + if (len <= DNAME_INLINE_LEN - 1) { > + memcpy(strbuf, str, len); > + strbuf[len] = 0; > + qstr.name = strbuf; > + /* prevent compiler from optimizing out the temporary buffer */ > + barrier(); > + } > + ret = utf8_strncasecmp(um, name, &qstr); > + 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(generic_ci_d_compare); > + > +/** > + * generic_ci_d_hash - generic d_hash implementation for casefolding filesystems > + * @dentry: dentry whose name we are hashing > + * @str: qstr of name whose hash we should fill in > + * > + * Return: 0 if hash was successful, or -ERRNO > + */ > +int generic_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; > + > + if (!inode || !needs_casefold(inode)) > + return 0; > + > + ret = utf8_casefold_hash(um, dentry, str); > + if (ret < 0) > + goto err; > + > + return 0; > +err: > + if (sb_has_enc_strict_mode(sb)) > + ret = -EINVAL; > + else > + ret = 0; > + return ret; > +} Maybe drop the err label and simplify: ret = utf8_casefold_hash(um, dentry, str); if (ret < 0 && sb_has_enc_strict_mode(sb)) return -EINVAL; return 0; > +EXPORT_SYMBOL(generic_ci_d_hash); > +#endif > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 3f881a892ea74..261904e06873b 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -1392,6 +1392,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 > */ > @@ -1461,6 +1467,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 */ > @@ -3385,6 +3395,18 @@ extern int generic_file_fsync(struct file *, loff_t, loff_t, int); > > extern int generic_check_addressable(unsigned, u64); > > +#ifdef CONFIG_UNICODE > +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 > + > #ifdef CONFIG_MIGRATION > extern int buffer_migrate_page(struct address_space *, > struct page *, struct page *, -- Gabriel Krisman Bertazi