• Gabriel Krisman Bertazi's avatar
    ext4: Support case-insensitive file name lookups · b886ee3e
    Gabriel Krisman Bertazi authored
    This patch implements the actual support for case-insensitive file name
    lookups in ext4, based on the feature bit and the encoding stored in the
    superblock.
    
    A filesystem that has the casefold feature set is able to configure
    directories with the +F (EXT4_CASEFOLD_FL) attribute, enabling lookups
    to succeed in that directory in a case-insensitive fashion, i.e: match
    a directory entry even if the name used by userspace is not a byte per
    byte match with the disk name, but is an equivalent case-insensitive
    version of the Unicode string.  This operation is called a
    case-insensitive file name lookup.
    
    The feature is configured as an inode attribute applied to directories
    and inherited by its children.  This attribute can only be enabled on
    empty directories for filesystems that support the encoding feature,
    thus preventing collision of file names that only differ by case.
    
    * dcache handling:
    
    For a +F directory, Ext4 only stores the first equivalent name dentry
    used in the dcache. This is done to prevent unintentional duplication of
    dentries in the dcache, while also allowing the VFS code to quickly find
    the right entry in the cache despite which equivalent string was used in
    a previous lookup, without having to resort to ->lookup().
    
    d_hash() of casefolded directories is implemented as the hash of the
    casefolded string, such that we always have a well-known bucket for all
    the equivalencies of the same string. d_compare() uses the
    utf8_strncasecmp() infrastructure, which handles the comparison of
    equivalent, same case, names as well.
    
    For now, negative lookups are not inserted in the dcache, since they
    would need to be invalidated anyway, because we can't trust missing file
    dentries.  This is bad for performance but requires some leveraging of
    the vfs layer to fix.  We can live without that for now, and so does
    everyone else.
    
    * on-disk data:
    
    Despite using a specific version of the name as the internal
    representation within the dcache, the name stored and fetched from the
    disk is a byte-per-byte match with what the user requested, making this
    implementation 'name-preserving'. i.e. no actual information is lost
    when writing to storage.
    
    DX is supported by modifying the hashes used in +F directories to make
    them case/encoding-aware.  The new disk hashes are calculated as the
    hash of the full casefolded string, instead of the string directly.
    This allows us to efficiently search for file names in the htree without
    requiring the user to provide an exact name.
    
    * Dealing with invalid sequences:
    
    By default, when a invalid UTF-8 sequence is identified, ext4 will treat
    it as an opaque byte sequence, ignoring the encoding and reverting to
    the old behavior for that unique file.  This means that case-insensitive
    file name lookup will not work only for that file.  An optional bit can
    be set in the superblock telling the filesystem code and userspace tools
    to enforce the encoding.  When that optional bit is set, any attempt to
    create a file name using an invalid UTF-8 sequence will fail and return
    an error to userspace.
    
    * Normalization algorithm:
    
    The UTF-8 algorithms used to compare strings in ext4 is implemented
    lives in fs/unicode, and is based on a previous version developed by
    SGI.  It implements the Canonical decomposition (NFD) algorithm
    described by the Unicode specification 12.1, or higher, combined with
    the elimination of ignorable code points (NFDi) and full
    case-folding (CF) as documented in fs/unicode/utf8_norm.c.
    
    NFD seems to be the best normalization method for EXT4 because:
    
      - It has a lower cost than NFC/NFKC (which requires
        decomposing to NFD as an intermediary step)
      - It doesn't eliminate important semantic meaning like
        compatibility decompositions.
    
    Although:
    
      - This implementation is not completely linguistic accurate, because
      different languages have conflicting rules, which would require the
      specialization of the filesystem to a given locale, which brings all
      sorts of problems for removable media and for users who use more than
      one language.
    Signed-off-by: default avatarGabriel Krisman Bertazi <krisman@collabora.co.uk>
    Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
    b886ee3e
inode.c 180 KB