Unicode/UTF-8 support for XFS
Subsystems (3)
Hi,
I'm posting this RFC for Unicode support in XFS on Olaf's behalf, as he is busy with other projects. This is the second revision of the series. The first is available here:
http://oss.sgi.com/archives/xfs/2014-09/msg00169.html
In response to the initial feedback, the changes in version 2 include:
* linux-fsdevel in the To: line,
* Updated design notes,
* Separation of the fs-independent trie and support code into utf8norm.ko,
* A mechanism for loading the normalization module only when necessary.
I'll post the whole series for completeness sake. Many on -fsdevel will not be interested in the xfs-specific bits, but it may be helpful to have the full series as an example and for testing purposes.
First there is a set of kernel bits, then some libxfs/xfsprogs stuff, and finally a test. (Note: I am not posting the unicode database files due to their large size. There are scripts to download them from unicode.org in the relevant commit headers.)
TODO: Store the unicode version number of the filesystem on disk in the super block.
Thanks,
Ben
Here are Olaf's design notes:
-----------------------------------------------------------------------------
Unicode/UTF-8 support for XFS
So we had a customer request proper unicode support...
* What does "supporting unicode" actually mean?
Quoted 1 line
From a text processing point of view, what a filesystem does with
filenames is simple: it stores and retrieves them, and compares them for equality. It may reject certain byte sequences as invalid filenames (for example, no filename can contain an ASCII NUL).
I've been taking it as a given that when a file is created with a certain byte sequence as its name, then a subsequent directory listing will contain that same byte sequence among the names listed.
This leaves comparing names for equality, and in my view this is what "supporting unicode" revolves about.
The present state of affairs is that different byte sequences are different filenames. This amounts to tolerating unicode without actually supporting it.
To support unicode we have to interpret filenames. What happens when (part of) a filename cannot be interpreted? We can reject the filename, interpret the parts we can, or punt and accept it as an uninterpreted blob.
Rejecting ill-formed filenames was my first choice, but I came around on the issue: there are too many ways in which you can end up with having to deal with ill-formed filenames that would leave a user with no recourse but to move whatever they're doing to a different filesystem. Unpacking a tarball with filenames in a different encoding is an example.
Partial interpretation of an ill-formed filename just strikes me as the kind of bad idea that most half-houses are. I admit that I have no stronger objection to this than the fact that it makes the code even more complicated and fragile.
Which leaves "blob" as the preferred option by default for coping with ill-formed filenames.
When comparing well-formed filenames, the question now becomes which byte sequences are considered to be alternative spellings of the same filename. This is where normalization forms come into play, and the unicode standard has quite a bit to say about the subject.
If all you're doing is comparison, then choosing NFD over NFC is easy, because the former is easier to calculate than the latter.
If you want various spellings of "office" to compare equal, then picking NFKD over NFD for comparison is also an obvious choice. (Hand-picking individual compatibility forms is truly a bad idea.) Ways to spell "office": "o_f_f_i_c_e", "o_f_fi_c_e", and "o_ffi_c_e", using no ligatures, the fi ligature, or the ffi ligature. (Some fool thought it a good idea to add these ligatures to unicode, all we get to decide is how to cope.)
The most contentious part is (should be) ignoring the codepoints with the Default_Ignorable_Code_Point property. I've included the list below. My argument, such as it is, is that these code points either have no visible rendering, or in cases like the soft hyphen, are only conditionally visible. The problem with these (as I see it) is that on seeing a filename that might contain them you cannot tell whether they are present. So I propose to ignore them for the purpose of comparing filenames for equality.
Finally, case folding. First of all, it is optional. Then the issue is that you either go the language-specific route, or simplify the task by "just" doing a full casefold (C+F, in unicode parlance). Looking around the net I tend to find that if you're going to do casefolding at all, then a language-independent full casefold is preferred because it is the most predictable option. See
http://www.w3.org/TR/charmod-norm/ for an example of that kind of reasoning.
An additional question is whether case folding should be a fixed (mkfs-time) property of a filesystem or can be enabled and disabled on the fly. When mixing these modes, preferring exact matches is easy. But after case-sensitive creates of files named "README" and "readme", which of these two files will be found by case-insensitive lookups of "Readme", and "ReadMe"? Does the answer differ if the order in which the files were created is reversed? I do not have good answers to those questions, and absent such answers the behavior of a filesystem becomes hard to predict. This may not be a bug according to the design, but it will be experienced as a bug by users. This is why in these patches case folding is a property set at mkfs time.
All of these choices can be argued with, but I do believe that the particular combination of choices I made is a defensible one.
The code refers to these normalization forms as nfkdi and nfkdicf.
* XFS-specific design notes.
XFS uses byte strings for filenames, so UTF-8 is the expected format for unicode filenames. This does raise the question what criteria a byte string must meet to be UTF-8. We settled on the following:
- Valid unicode code points are 0..0x10FFFF, except that
- The surrogates 0xD800..0xDFFF are not valid code points, and
- Valid UTF-8 must be a shortest encoding of a valid unicode code point.
In addition, U+0 (ASCII NUL, '\0') is used to terminate byte strings (and is itself not part of the string). Moreover strings may be length-limited in addition to being NUL-terminated (there is no such thing as an embedded NUL in a length-limited string).
The code uses ("leverages", in corp-speak) the existing XFS infrastructure for case-insensitive filenames. Like the CI code, the name used to create a file is stored on disk, and returned in a lookup. When comparing filenames the normalized forms of the names being compared are generated on the fly from the non-normalized forms stored on disk.
If the borgbit (the bit enabling legacy ASCII-based CI in XFS) is set in the superblock, then case folding is added into the mix. This is the nfkdicf normalization form mentioned above. It allows for the creation of case-insensitive filesystems with UTF-8 support.
* Implementation notes.
Strings are normalized using a trie that stores the relevant information. The trie itself is about 250kB in size, and lives in a separate module. The trie is not checked in: instead we add the source files from the Unicode Character Database and a program that creates the header containing the trie.
The key for a lookup in the trie is a UTF-8 sequence. Each valid UTF-8 sequence leads to a leaf. No invalid sequence does. This means that trie lookups can be used to validate UTF-8 sequences, which why there is no specialized code for the same purpose.
The trie contains information for the version of unicode in which each code point was defined. This matters because non-normalized strings are stored on disk, and newer versions of unicode may introduce new normalized forms. Ideally, the version of unicode used by the filesystem is stored in the filesystem.
The trie also accounts for corrections made in the past to normalizations. This has little value today, because any newly created filesystem would be using unicode version 7.0.0. It is included in order to show, not tell, that such corrections can be handled if they are added in future revisions.
The algorithm used to calculate the sequences of bytes for the normalized form of a UTF-8 string is tricky. The core is found in utf8byte(), with an explanation in the preceeding comment.
The non-XFS-specific supporting code functions have the prefix 'utf8n' if they handle length-limited strings, and 'utf8' if they handle NUL-terminated strings.
----
# Derived Property: Default_Ignorable_Code_Point
# Generated from
# Other_Default_Ignorable_Code_Point
# + Cf (Format characters) # + Variation_Selector # - White_Space # - FFF9..FFFB (Annotation Characters) # - 0600..0605, 06DD, 070F, 110BD (exceptional Cf characters that should be visible)
00AD ; Default_Ignorable_Code_Point # Cf SOFT HYPHEN 034F ; Default_Ignorable_Code_Point # Mn COMBINING GRAPHEME JOINER 061C ; Default_Ignorable_Code_Point # Cf ARABIC LETTER MARK 115F..1160 ; Default_Ignorable_Code_Point # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER 17B4..17B5 ; Default_Ignorable_Code_Point # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA 180B..180D ; Default_Ignorable_Code_Point # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE 180E ; Default_Ignorable_Code_Point # Cf MONGOLIAN VOWEL SEPARATOR 200B..200F ; Default_Ignorable_Code_Point # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK 202A..202E ; Default_Ignorable_Code_Point # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE 2060..2064 ; Default_Ignorable_Code_Point # Cf [5] WORD JOINER..INVISIBLE PLUS 2065 ; Default_Ignorable_Code_Point # Cn <reserved-2065> 2066..206F ; Default_Ignorable_Code_Point # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES 3164 ; Default_Ignorable_Code_Point # Lo HANGUL FILLER FE00..FE0F ; Default_Ignorable_Code_Point # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 FEFF ; Default_Ignorable_Code_Point # Cf ZERO WIDTH NO-BREAK SPACE FFA0 ; Default_Ignorable_Code_Point # Lo HALFWIDTH HANGUL FILLER FFF0..FFF8 ; Default_Ignorable_Code_Point # Cn [9] <reserved-FFF0>..<reserved-FFF8> 1BCA0..1BCA3 ; Default_Ignorable_Code_Point # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP 1D173..1D17A ; Default_Ignorable_Code_Point # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE E0000 ; Default_Ignorable_Code_Point # Cn <reserved-E0000> E0001 ; Default_Ignorable_Code_Point # Cf LANGUAGE TAG E0002..E001F ; Default_Ignorable_Code_Point # Cn [30] <reserved-E0002>..<reserved-E001F> E0020..E007F ; Default_Ignorable_Code_Point # Cf [96] TAG SPACE..CANCEL TAG E0080..E00FF ; Default_Ignorable_Code_Point # Cn [128] <reserved-E0080>..<reserved-E00FF> E0100..E01EF ; Default_Ignorable_Code_Point # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 E01F0..E0FFF ; Default_Ignorable_Code_Point # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
# Total code points: 4173
----
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 1/10 xfs: return the first match during case-insensitive lookup.
From: Olaf Weber <[email protected]>
Change the XFS case-insensitive lookup code to return the first match found, even if it is not an exact match. Whether a filesystem uses case-insensitive lookups is determined by a superblock bit set during filesystem creation. This means that normal use cannot create two files that both match the same filename.
--- fs/xfs/libxfs/xfs_dir2_block.c | 17 +++------ fs/xfs/libxfs/xfs_dir2_leaf.c | 37 ++++---------------- fs/xfs/libxfs/xfs_dir2_node.c | 79 ++++++++++++++++-------------------------- fs/xfs/libxfs/xfs_dir2_sf.c | 8 ++--- 4 files changed, 45 insertions(+), 96 deletions(-)
fs/xfs/libxfs/xfs_dir2_block.c +5 -12
@@ -725,28 +725,21 @@ xfs_dir2_block_lookup_int( dep = (xfs_dir2_data_entry_t *) ((char *)hdr +xfs_dir2_dataptr_to_off (args->geo, addr));/* -* Compare name and if it's an exact match, return the index -* and buffer. If it's the first case-insensitive match, store -* the index and buffer and continue looking for an exact match. +* Compare name and if it's a match, return the +* index and buffer. */ cmp = mp->m_dirnameops->compname (args, dep->name, dep->namelen); -if (cmp !=XFS_CMP_DIFFERENT && cmp != args->cmpresult) { +if (cmp !=XFS_CMP_DIFFERENT ) { args->cmpresult = cmp; *bpp = bp; *entno = mid; -if (cmp ==XFS_CMP_EXACT ) -return 0 ; +return 0 ; } }while (++mid <be32_to_cpu (btp->count) &&be32_to_cpu (blp[mid].hashval) == hash);ASSERT (args->op_flags &XFS_DA_OP_OKNOENT ); -/* -* Here, we can only be doing a lookup (not a rename or replace). -* If a case-insensitive match was found earlier, return success. -*/ -if (args->cmpresult ==XFS_CMP_CASE ) -return 0 ; +ASSERT (args->cmpresult ==XFS_CMP_DIFFERENT );/* * No match, release the buffer and return ENOENT. */
fs/xfs/libxfs/xfs_dir2_leaf.c +6 -31
@@ -1226,7 +1226,6 @@ xfs_dir2_leaf_lookup_int(xfs_mount_t *mp;/* filesystem mount point */ xfs_dir2_db_t newdb;/* new data block number */ xfs_trans_t *tp;/* transaction pointer */ -xfs_dir2_db_t cidb =-1 ;/* case match data block no. */ enum xfs_dacmp cmp;/* name compare result */ struct xfs_dir2_leaf_entry *ents;struct xfs_dir3_icleaf_hdr leafhdr;
@@ -1290,46 +1289,22 @@ xfs_dir2_leaf_lookup_int( be32_to_cpu(lep->address)));/* * Compare name and if it's an exact match, return the index -* and buffer. If it's the first case-insensitive match, store -* the index and buffer and continue looking for an exact match. +* and buffer */ cmp = mp->m_dirnameops->compname (args, dep->name, dep->namelen); -if (cmp !=XFS_CMP_DIFFERENT && cmp != args->cmpresult) { +if (cmp !=XFS_CMP_DIFFERENT ) { args->cmpresult = cmp; *indexp = index; -/* case exact match: return the current buffer. */ -if (cmp ==XFS_CMP_EXACT ) { - *dbpp = dbp; -return 0 ; - } - cidb = curdb; + *dbpp = dbp; +return 0 ; } }ASSERT (args->op_flags &XFS_DA_OP_OKNOENT ); -/* -* Here, we can only be doing a lookup (not a rename or remove). -* If a case-insensitive match was found earlier, re-read the -* appropriate data block if required and return it. -*/ -if (args->cmpresult ==XFS_CMP_CASE ) { -ASSERT (cidb !=-1 ); -if (cidb != curdb) { -xfs_trans_brelse (tp, dbp); - error =xfs_dir3_data_read (tp, dp, -xfs_dir2_db_to_da (args->geo, cidb), --1 , &dbp); -if (error) { -xfs_trans_brelse (tp, lbp); -return error; - } - } - *dbpp = dbp; -return 0 ; - } +ASSERT (args->cmpresult ==XFS_CMP_DIFFERENT ); +/* * No match found, return -ENOENT. */ -ASSERT (cidb ==-1 );if (dbp)xfs_trans_brelse (tp, dbp);xfs_trans_brelse (tp, lbp);
fs/xfs/libxfs/xfs_dir2_node.c +30 -49
123 lines not on this page · raw message
fs/xfs/libxfs/xfs_dir2_sf.c +4 -4
@@ -757,19 +757,19 @@ xfs_dir2_sf_lookup(for (i =0 , sfep =xfs_dir2_sf_firstentry (sfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry (sfp, sfep)) {/* -* Compare name and if it's an exact match, return the inode -* number. If it's the first case-insensitive match, store the -* inode number and continue looking for an exact match. +* Compare name and if it's a match, return the inode +* number. */ cmp = dp->i_mount->m_dirnameops->compname (args, sfep->name, sfep->namelen); -if (cmp !=XFS_CMP_DIFFERENT && cmp != args->cmpresult) { +if (cmp !=XFS_CMP_DIFFERENT ) { args->cmpresult = cmp; args->inumber = dp->d_ops->sf_get_ino (sfp, sfep); args->filetype = dp->d_ops->sf_get_ftype (sfep);if (cmp ==XFS_CMP_EXACT )return -EEXIST ; ci_sfep = sfep; +break ; } }ASSERT (args->op_flags &XFS_DA_OP_OKNOENT );
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 2/10 xfs: rename XFS_CMP_CASE to XFS_CMP_MATCH
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Rename XFS_CMP_CASE to XFS_CMP_MATCH. With unicode filenames and normalization, different strings will match on other criteria than case insensitivity.
--- fs/xfs/libxfs/xfs_da_btree.h | 2 +- fs/xfs/libxfs/xfs_dir2.c | 9 ++++++--- fs/xfs/libxfs/xfs_dir2_node.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-)
fs/xfs/libxfs/xfs_da_btree.h +1 -1
@@ -52,7 +52,7 @@ struct xfs_da_geometry {enum xfs_dacmp {XFS_CMP_DIFFERENT ,/* names are completely different */ XFS_CMP_EXACT ,/* names are exactly the same */ -XFS_CMP_CASE /* names are same but differ in case */ +XFS_CMP_MATCH /* names are same but differ in encoding */ };/*
fs/xfs/libxfs/xfs_dir2.c +6 -3
@@ -74,7 +74,7 @@ xfs_ascii_ci_compname(continue ;if (tolower (args->name[i]) !=tolower (name[i]))return XFS_CMP_DIFFERENT ; - result =XFS_CMP_CASE ; + result =XFS_CMP_MATCH ; }return result;
@@ -315,8 +315,11 @@ xfs_dir_cilookup_result( {if (args->cmpresult ==XFS_CMP_DIFFERENT )return -ENOENT ; -if (args->cmpresult !=XFS_CMP_CASE || - !(args->op_flags &XFS_DA_OP_CILOOKUP )) +if (args->cmpresult ==XFS_CMP_EXACT ) +return -EEXIST ; +ASSERT (args->cmpresult ==XFS_CMP_MATCH ); +/* Only dup the found name if XFS_DA_OP_CILOOKUP is set. */ +if (!(args->op_flags &XFS_DA_OP_CILOOKUP ))return -EEXIST ; args->value =kmem_alloc (len,KM_NOFS |KM_MAYFAIL );
fs/xfs/libxfs/xfs_dir2_node.c +1 -1
@@ -2023,7 +2023,7 @@ xfs_dir2_node_lookup( error =xfs_da3_node_lookup_int (state, &rval);if (error) rval = error; -else if (rval == -ENOENT && args->cmpresult ==XFS_CMP_CASE ) { +else if (rval == -ENOENT && args->cmpresult ==XFS_CMP_MATCH ) {/* If a CI match, dup the actual name and return -EEXIST */ xfs_dir2_data_entry_t *dep;
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 3/13 libxfs: add xfs_nameops.normhash
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Add a normhash callout to the xfs_nameops. This callout takes an xfs_da_args structure as its argument, and calculates a hash value over the name. It may in the process create a normalized form of the name, and assign that to the norm/normlen fields in the xfs_da_args structure.
Changes:
The pointer in kmem_free() was type converted to suppress compiler warnings.
--- include/xfs_da_btree.h | 5 ++++- libxfs/xfs_da_btree.c | 9 ++++++++ libxfs/xfs_dir2.c | 56 +++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 57 insertions(+), 13 deletions(-)
include/xfs_da_btree.h +4 -1
@@ -42,7 +42,9 @@ enum xfs_dacmp {*/ typedef struct xfs_da_args { const __uint8_t *name; /* string (maybe not NULL terminated) */ - int namelen; /* length of string (maybe no NULL) */ + const __uint8_t *norm; /* normalized name (may be NULL) */ + int namelen; /* length of string (maybe no NULL) */ + int normlen; /* length of normalized name */ __uint8_t filetype; /* filetype of inode for directories */ __uint8_t *value; /* set of bytes (maybe contain NULLs) */ int valuelen; /* length of value */
@@ -131,6 +133,7 @@ typedef struct xfs_da_state {*/ struct xfs_nameops {xfs_dahash_t (*hashname)(struct xfs_name *); +int (*normhash)(struct xfs_da_args *);enum xfs_dacmp (*compname)(struct xfs_da_args *,const unsigned char *,int ); };
libxfs/xfs_da_btree.c +9 -0
@@ -2000,8 +2000,17 @@ xfs_default_hashname(return xfs_da_hashname (name->name, name->len); } +STATIC int +xfs_da_normhash ( +struct xfs_da_args *args) +{ + args->hashval =xfs_da_hashname (args->name, args->namelen); +return 0 ; +} +const struct xfs_nameops xfs_default_nameops = { .hashname = xfs_default_hashname, + .normhash = xfs_da_normhash, .compname = xfs_da_compname };
libxfs/xfs_dir2.c +44 -12
162 lines not on this page · raw message
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 3/10 xfs: add xfs_nameops.normhash
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Add a normhash callout to the xfs_nameops. This callout takes an xfs_da_args structure as its argument, and calculates a hash value over the name. It may in the process create a normalized form of the name, and assign that to the norm/normlen fields in the xfs_da_args structure.
--- fs/xfs/libxfs/xfs_da_btree.c | 9 +++++++++ fs/xfs/libxfs/xfs_da_btree.h | 3 +++ fs/xfs/libxfs/xfs_dir2.c | 42 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 5 deletions(-)
fs/xfs/libxfs/xfs_da_btree.c +9 -0
@@ -1990,8 +1990,17 @@ xfs_default_hashname(return xfs_da_hashname (name->name, name->len); } +STATIC int +xfs_da_normhash ( +struct xfs_da_args *args) +{ + args->hashval =xfs_da_hashname (args->name, args->namelen); +return 0 ; +} +const struct xfs_nameops xfs_default_nameops = { .hashname = xfs_default_hashname, + .normhash = xfs_da_normhash, .compname = xfs_da_compname };
fs/xfs/libxfs/xfs_da_btree.h +3 -0
@@ -61,7 +61,9 @@ enum xfs_dacmp { typedef struct xfs_da_args { struct xfs_da_geometry *geo; /* da block geometry */ const __uint8_t *name; /* string (maybe not NULL terminated) */ + const __uint8_t *norm; /* normalized name (may be NULL) */ int namelen; /* length of string (maybe no NULL) */ + int normlen; /* length of normalized name */ __uint8_t filetype; /* filetype of inode for directories */ __uint8_t *value; /* set of bytes (maybe contain NULLs) */ int valuelen; /* length of value */
@@ -150,6 +152,7 @@ typedef struct xfs_da_state {*/ struct xfs_nameops {xfs_dahash_t (*hashname)(struct xfs_name *); +int (*normhash)(struct xfs_da_args *);enum xfs_dacmp (*compname)(struct xfs_da_args *,const unsigned char *,int ); };
fs/xfs/libxfs/xfs_dir2.c +37 -5
143 lines not on this page · raw message
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 4/10 xfs: change interface of xfs_nameops.normhash
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
With the introduction of the xfs_nameops.normhash callout, all uses of the hashname callout now occur in places where an xfs_name structure must be explicitly created just to match the parameter passing convention of this callout. Change the arguments to a const unsigned char * and int instead.
--- fs/xfs/libxfs/xfs_da_btree.c | 9 +-------- fs/xfs/libxfs/xfs_da_btree.h | 2 +- fs/xfs/libxfs/xfs_dir2.c | 7 ++++--- fs/xfs/libxfs/xfs_dir2_block.c | 2 +- fs/xfs/libxfs/xfs_dir2_data.c | 3 ++- 5 files changed, 9 insertions(+), 14 deletions(-)
fs/xfs/libxfs/xfs_da_btree.c +1 -8
@@ -1983,13 +1983,6 @@ xfs_da_compname( XFS_CMP_EXACT :XFS_CMP_DIFFERENT ; } -static xfs_dahash_t -xfs_default_hashname ( -struct xfs_name *name) -{ -return xfs_da_hashname (name->name, name->len); -} - STATIC intxfs_da_normhash (struct xfs_da_args *args)
@@ -1999,7 +1992,7 @@ xfs_da_normhash( }const struct xfs_nameops xfs_default_nameops = { - .hashname = xfs_default_hashname, + .hashname = xfs_da_hashname, .normhash = xfs_da_normhash, .compname = xfs_da_compname };
fs/xfs/libxfs/xfs_da_btree.h +1 -1
@@ -151,7 +151,7 @@ typedef struct xfs_da_state {* Name ops for directory and/or attr name operations */ struct xfs_nameops { -xfs_dahash_t (*hashname)(struct xfs_name *); +xfs_dahash_t (*hashname)(const unsigned char *,int );int (*normhash)(struct xfs_da_args *);enum xfs_dacmp (*compname)(struct xfs_da_args *,const unsigned char *,int );
fs/xfs/libxfs/xfs_dir2.c +4 -3
@@ -45,13 +45,14 @@ struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };*/ STATIC xfs_dahash_txfs_ascii_ci_hashname ( -struct xfs_name *name) +const unsigned char *name, +int len) {xfs_dahash_t hash;int i; -for (i =0 , hash =0 ; i < name->len; i++) - hash =tolower (name->name[i]) ^rol32 (hash,7 ); +for (i =0 , hash =0 ; i < len; i++) + hash =tolower (name[i]) ^rol32 (hash,7 );return hash; }
fs/xfs/libxfs/xfs_dir2_block.c +1 -1
@@ -1231,7 +1231,7 @@ xfs_dir2_sf_to_block( name.name = sfep->name; name.len = sfep->namelen; blp[2 + i].hashval =cpu_to_be32 (mp->m_dirnameops-> -hashname (&name)); +hashname (sfep->name, sfep->namelen)); blp[2 + i].address =cpu_to_be32 (xfs_dir2_byte_to_dataptr ( (char *)dep - (char *)hdr)); offset = (int )((char *)(tagp +1 ) - (char *)hdr);
fs/xfs/libxfs/xfs_dir2_data.c +2 -1
@@ -179,7 +179,8 @@ __xfs_dir3_data_check( ((char *)dep - (char *)hdr)); name.name = dep->name; name.len = dep->namelen; - hash = mp->m_dirnameops->hashname (&name); + hash = mp->m_dirnameops->hashname (dep->name, + dep->namelen);for (i =0 ; i <be32_to_cpu (btp->count); i++) {if (be32_to_cpu (lep[i].address) == addr &&be32_to_cpu (lep[i].hashval) == hash)
Signature · 1 line
1.7.12.4
PATCH 5/10 xfs: add a superblock feature bit to indicate UTF-8 support.
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
When UTF-8 support is enabled, the xfs_dir_ci_inode_operations must be installed. Add xfs_sb_version_hasci(), which tests both the borgbit and the utf8bit, and returns true if at least one of them is set. Replace calls to xfs_sb_version_hasasciici() as needed.
--- fs/xfs/libxfs/xfs_sb.h | 24 +++++++++++++++++++++++- fs/xfs/xfs_fs.h | 1 + fs/xfs/xfs_fsops.c | 4 +++- fs/xfs/xfs_iops.c | 4 ++-- 4 files changed, 29 insertions(+), 4 deletions(-)
fs/xfs/libxfs/xfs_sb.h +23 -1
@@ -70,6 +70,7 @@ struct xfs_trans;#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004#define XFS_SB_VERSION2_ATTR2BIT 0x00000008/* Inline attr rework */ #define XFS_SB_VERSION2_PARENTBIT 0x00000010/* parent pointers */ +#define XFS_SB_VERSION2_UTF8BIT 0x00000020/* utf8 names */ #define XFS_SB_VERSION2_PROJID32BIT 0x00000080/* 32 bit project id */ #define XFS_SB_VERSION2_CRCBIT 0x00000100/* metadata CRCs */ #define XFS_SB_VERSION2_FTYPE 0x00000200/* inode type in dir */
@@ -77,6 +78,7 @@ struct xfs_trans;#define XFS_SB_VERSION2_OKBITS \ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \ XFS_SB_VERSION2_ATTR2BIT | \ + XFS_SB_VERSION2_UTF8BIT | \ XFS_SB_VERSION2_PROJID32BIT | \ XFS_SB_VERSION2_FTYPE)
@@ -509,8 +511,10 @@ xfs_sb_has_ro_compat_feature( }#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0)/* filetype in dirent */ +#define XFS_SB_FEAT_INCOMPAT_UTF8 (1 << 1)/* utf-8 name support */ #define XFS_SB_FEAT_INCOMPAT_ALL \ - (XFS_SB_FEAT_INCOMPAT_FTYPE) + (XFS_SB_FEAT_INCOMPAT_FTYPE | \ + XFS_SB_FEAT_INCOMPAT_UTF8)#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL static inline bool
@@ -558,6 +562,24 @@ static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp) (sbp->sb_features_ro_compat &XFS_SB_FEAT_RO_COMPAT_FINOBT ); } +static inline int xfs_sb_version_hasutf8 (xfs_sb_t *sbp) +{ +return (XFS_SB_VERSION_NUM (sbp) ==XFS_SB_VERSION_5 && +xfs_sb_has_incompat_feature (sbp,XFS_SB_FEAT_INCOMPAT_UTF8 )) || + (xfs_sb_version_hasmorebits (sbp) && + (sbp->sb_features2 &XFS_SB_VERSION2_UTF8BIT )); +} + +/* +* Special case: there are a number of places where we need to test +* both the borgbit and the utf8bit, and take the same action if +* either of those is set. +*/ +static inline int xfs_sb_version_hasci (xfs_sb_t *sbp) +{ +return xfs_sb_version_hasasciici (sbp) ||xfs_sb_version_hasutf8 (sbp); +} +/* * end of superblock version macros */
fs/xfs/xfs_fs.h +1 -0
@@ -239,6 +239,7 @@ typedef struct xfs_fsop_resblks {#define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000/* version 5 superblock */ #define XFS_FSOP_GEOM_FLAGS_FTYPE 0x10000/* inode directory types */ #define XFS_FSOP_GEOM_FLAGS_FINOBT 0x20000/* free inode btree */ +#define XFS_FSOP_GEOM_FLAGS_UTF8 0x40000/* utf8 filenames */ /* * Minimum and maximum sizes need for growth checks.
fs/xfs/xfs_fsops.c +3 -1
@@ -103,7 +103,9 @@ xfs_fs_geometry( (xfs_sb_version_hasftype (&mp->m_sb) ?XFS_FSOP_GEOM_FLAGS_FTYPE :0 ) | (xfs_sb_version_hasfinobt (&mp->m_sb) ? -XFS_FSOP_GEOM_FLAGS_FINOBT :0 ); +XFS_FSOP_GEOM_FLAGS_FINOBT :0 ) | + (xfs_sb_version_hasutf8 (&mp->m_sb) ? +XFS_FSOP_GEOM_FLAGS_UTF8 :0 ); geo->logsectsize =xfs_sb_version_hassector (&mp->m_sb) ? mp->m_sb.sb_logsectsize :BBSIZE ; geo->rtsectsize = mp->m_sb.sb_blocksize;
fs/xfs/xfs_iops.c +2 -2
@@ -335,9 +335,9 @@ xfs_vn_unlink(/* * With unlink, the VFS makes the dentry "negative": no inode, * but still hashed. This is incompatible with case-insensitive -* mode, so invalidate (unhash) the dentry in CI-mode. +* or utf8 mode, so invalidate (unhash) the dentry in CI-mode. */ -if (xfs_sb_version_hasasciici (&XFS_M (dir->i_sb)->m_sb)) +if (xfs_sb_version_hasci (&XFS_M (dir->i_sb)->m_sb))d_invalidate (dentry);return 0 ; }
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 6/10 xfs: add unicode character database files
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Add files from the Unicode Character Database, version 7.0.0, to the source. A helper program that generates a trie used for normalization from these files is part of a separate commit.
---
[v2: Removed large unicode files prior to posting. Get them as below. -bpm] [v3: Moved files to ucd8norm directory. -bpm]
cd fs/xfs/utf8norm/ucd
wget http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt
wget http://www.unicode.org/Public/7.0.0/ucd/DerivedAge.txt
wget http://www.unicode.org/Public/7.0.0/ucd/extracted/DerivedCombiningClass.txt
wget http://www.unicode.org/Public/7.0.0/ucd/DerivedCoreProperties.txt
wget http://www.unicode.org/Public/7.0.0/ucd/NormalizationCorrections.txt
wget http://www.unicode.org/Public/7.0.0/ucd/NormalizationTest.txt
wget http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt
for e in *.txt
do
base=`basename $e .txt` mv $e $base-7.0.0.txt done --- fs/xfs/utf8norm/ucd/README | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 fs/xfs/utf8norm/ucd/README
fs/xfs/utf8norm/ucd/README new file +33 -0
@@ -0,0 +1,33 @@ +The files in this directory are part of the Unicode Character Database +for version 7.0.0 of the Unicode standard. + +The full set of files can be found here: + + http://www.unicode.org/Public/7.0.0/ucd/ + +The latest released version of the UCD can be found here: + + http://www.unicode.org/Public/UCD/latest/ + +The files in this directory are identical, except that they have been +renamed with a suffix indicating the unicode version. + +Individual source links: + + http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt + http://www.unicode.org/Public/7.0.0/ucd/DerivedAge.txt + http://www.unicode.org/Public/7.0.0/ucd/extracted/DerivedCombiningClass.txt + http://www.unicode.org/Public/7.0.0/ucd/DerivedCoreProperties.txt + http://www.unicode.org/Public/7.0.0/ucd/NormalizationCorrections.txt + http://www.unicode.org/Public/7.0.0/ucd/NormalizationTest.txt + http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt + +md5sums + + 9a92b2bfe56c6719def926bab524fefd CaseFolding-7.0.0.txt + 07b8b1027eb824cf0835314e94f23d2e DerivedAge-7.0.0.txt + 90c3340b16821e2f2153acdbe6fc6180 DerivedCombiningClass-7.0.0.txt + c41c0601f808116f623de47110ed4f93 DerivedCoreProperties-7.0.0.txt + 522720ddfc150d8e63a2518634829bce NormalizationCorrections-7.0.0.txt + 1f35175eba4a2ad795db489f789ae352 NormalizationTest-7.0.0.txt + c8355655731d75e6a3de8c20d7e601ba UnicodeData-7.0.0.txt
Signature · 1 line
1.7.12.4
Re: [PATCH 06/10] xfs: add unicode character database files
Quoted 21 lines · Ben Myers
From: Olaf Weber <[email protected]>
Add files from the Unicode Character Database, version 7.0.0, to the source. A helper program that generates a trie used for normalization from these files is part of a separate commit.
Signed-off-by Olaf Weber <[email protected]>---
[v2: Removed large unicode files prior to posting. Get them as below. -bpm] [v3: Moved files to ucd8norm directory. -bpm]cd
fs/xfs/utf8norm/ucd
wget http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt
wget http://www.unicode.org/Public/7.0.0/ucd/DerivedAge.txt
wget http://www.unicode.org/Public/7.0.0/ucd/extracted/DerivedCombiningClass.txt
wget http://www.unicode.org/Public/7.0.0/ucd/DerivedCoreProperties.txt
wget http://www.unicode.org/Public/7.0.0/ucd/NormalizationCorrections.txt
wget http://www.unicode.org/Public/7.0.0/ucd/NormalizationTest.txt
wget http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt
for e in *.txt
do
Quoted 5 lines
base=`basename $e .txt` mv $e $base-7.0.0.txt done --- fs/xfs/utf8norm/ucd/README | 33 +++++++++++++++++++++++++++++++++
This probably needs to live somewhere under lib/. There's nothing XFS specific in it and the translations should be the same for anything that wants to parse unicode.
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Re: [PATCH 06/10] xfs: add unicode character database files
Quoted 3 lines · Dave Chinner
This probably needs to live somewhere under
lib/. There's nothing XFS specific in it and the translations should be the same for anything that wants to parse unicode.
Agreed.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 7/10 xfs: add trie generator and supporting code for UTF-8.
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
mkutf8data.c is the source for a program that generates utf8data.h, which contains the trie that utf8norm.c uses. The trie is generated from the Unicode 7.0.0 data files. The format of the utf8data[] table is described in utf8norm.c.
Supporting functions for UTF-8 normalization are in utf8norm.c with the header utf8norm.h. Two normalization forms are supported: nfkdi and nfkdicf.
nfkdi:
- Apply unicode normalization form NFKD.
- Remove any Default_Ignorable_Code_Point.
nfkdicf:
- Apply unicode normalization form NFKD.
- Remove any Default_Ignorable_Code_Point.
- Apply a full casefold (C + F).
For the purposes of the code, a string is valid UTF-8 if:
- The values encoded are 0x1..0x10FFFF.
- The surrogate codepoints 0xD800..0xDFFFF are not encoded.
- The shortest possible encoding is used for all values.
The supporting functions work on null-terminated strings (utf8 prefix) and on length-limited strings (utf8n prefix).
---
[v2: the trie is now separated into utf8norm.ko;
utf8version is now a function and exported;
introduced CONFIG_XFS_UTF8. -bpm]
--- fs/xfs/Kconfig | 8 + fs/xfs/Makefile | 2 +- fs/xfs/utf8norm/Makefile | 37 + fs/xfs/utf8norm/mkutf8data.c | 3239 ++++++++++++++++++++++++++++++++++++++++++ fs/xfs/utf8norm/utf8norm.c | 649 +++++++++ fs/xfs/utf8norm/utf8norm.h | 116 ++ 6 files changed, 4050 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/utf8norm/Makefile create mode 100644 fs/xfs/utf8norm/mkutf8data.c create mode 100644 fs/xfs/utf8norm/utf8norm.c create mode 100644 fs/xfs/utf8norm/utf8norm.h
fs/xfs/Kconfig +8 -0
@@ -95,3 +95,11 @@ config XFS_DEBUG not useful unless you are debugging a particular problem. Say N unless you are an XFS developer, or you play one on TV. + +config XFS_UTF8 + bool "XFS UTF-8 support" + depends on XFS_FS + help + Say Y here to enable utf8 normalization support in XFS. You + will be able to mount and use filesystems created with the + utf8 mkfs.xfs option.
fs/xfs/Makefile +1 -1
@@ -21,7 +21,7 @@ ccflags-y += -I$(src)/libxfs ccflags-$(CONFIG_XFS_DEBUG) += -g -obj-$(CONFIG_XFS_FS) += xfs.o +obj-$(CONFIG_XFS_FS) += xfs.o utf8norm/ # this one should be compiled first, as the tracing macros can easily blow up xfs-y += xfs_trace.o
fs/xfs/utf8norm/Makefile new file +37 -0
@@ -0,0 +1,37 @@ +# +# Copyright (c) 2014 SGI. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +ifeq ($(CONFIG_XFS_UTF8),y) +obj-m += utf8norm.o +endif + +hostprogs-y := mkutf8data +$(obj)/utf8norm.o: $(obj)/utf8data.h +$(obj)/utf8data.h: $(src)/ucd/*.txt +$(obj)/utf8data.h: $(obj)/mkutf8data FORCE + $(call if_changed,mkutf8data) +quiet_cmd_mkutf8data = MKUTF8DATA $@ + cmd_mkutf8data = $(obj)/mkutf8data \ + -a $(src)/ucd/DerivedAge-7.0.0.txt \ + -c $(src)/ucd/DerivedCombiningClass-7.0.0.txt \ + -p $(src)/ucd/DerivedCoreProperties-7.0.0.txt \ + -d $(src)/ucd/UnicodeData-7.0.0.txt \ + -f $(src)/ucd/CaseFolding-7.0.0.txt \ + -n $(src)/ucd/NormalizationCorrections-7.0.0.txt \ + -t $(src)/ucd/NormalizationTest-7.0.0.txt \ + -o $@
fs/xfs/utf8norm/mkutf8data.c new file +3239 -0
2,944 lines not on this page · raw message
fs/xfs/utf8norm/utf8norm.c new file +649 -0
649 lines not on this page · raw message
fs/xfs/utf8norm/utf8norm.h new file +116 -0
116 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Part of the diff is not shown here. View the raw message.
Re: [PATCH 07/10] xfs: add trie generator and supporting code for UTF-8.
Quoted 34 lines · Ben Myers
From: Olaf Weber <[email protected]>
mkutf8data.cis the source for a program that generatesutf8data.h, which contains the trie thatutf8norm.cuses. The trie is generated from the Unicode 7.0.0 data files. The format of the utf8data[] table is described inutf8norm.c.Supporting functions for UTF-8 normalization are in
utf8norm.cwith the headerutf8norm.h. Two normalization forms are supported: nfkdi and nfkdicf.nfkdi:
- Apply unicode normalization form NFKD.
- Remove anyDefault_Ignorable_Code_Point.nfkdicf:
- Apply unicode normalization form NFKD.
- Remove anyDefault_Ignorable_Code_Point.
- Apply a full casefold (C + F).For the purposes of the code, a string is valid UTF-8 if:
- The values encoded are 0x1..0x10FFFF.
- The surrogate codepoints 0xD800..0xDFFFF are not encoded.
- The shortest possible encoding is used for all values.The supporting functions work on null-terminated strings (utf8 prefix) and on length-limited strings (utf8n prefix).
Signed-off-by Olaf Weber <[email protected]>---
[v2: the trie is now separated into utf8norm.ko;
utf8version is now a function and exported;
introducedCONFIG_XFS_UTF8. -bpm]
Quoted 7 lines
--- fs/xfs/Kconfig | 8 + fs/xfs/Makefile | 2 +- fs/xfs/utf8norm/Makefile | 37 + fs/xfs/utf8norm/mkutf8data.c | 3239 ++++++++++++++++++++++++++++++++++++++++++ fs/xfs/utf8norm/utf8norm.c | 649 +++++++++ fs/xfs/utf8norm/utf8norm.h | 116 ++
Again, nothing XFS specific here. It's being built as a separate module and the only thing that XFS uses are exported functions, so it really should be generic library code....
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Re: [PATCH 07/10] xfs: add trie generator and supporting code for UTF-8.
Quoted 43 lines · Dave Chinner
Quoted 34 lines · Ben Myers
From: Olaf Weber <[email protected]>
mkutf8data.cis the source for a program that generatesutf8data.h, which contains the trie thatutf8norm.cuses. The trie is generated from the Unicode 7.0.0 data files. The format of the utf8data[] table is described inutf8norm.c.Supporting functions for UTF-8 normalization are in
utf8norm.cwith the headerutf8norm.h. Two normalization forms are supported: nfkdi and nfkdicf.nfkdi:
- Apply unicode normalization form NFKD.
- Remove anyDefault_Ignorable_Code_Point.nfkdicf:
- Apply unicode normalization form NFKD.
- Remove anyDefault_Ignorable_Code_Point.
- Apply a full casefold (C + F).For the purposes of the code, a string is valid UTF-8 if:
- The values encoded are 0x1..0x10FFFF.
- The surrogate codepoints 0xD800..0xDFFFF are not encoded.
- The shortest possible encoding is used for all values.The supporting functions work on null-terminated strings (utf8 prefix) and on length-limited strings (utf8n prefix).
Signed-off-by Olaf Weber <[email protected]>---
[v2: the trie is now separated into utf8norm.ko;
utf8version is now a function and exported;
introducedCONFIG_XFS_UTF8. -bpm]Quoted 7 lines
--- fs/xfs/Kconfig | 8 + fs/xfs/Makefile | 2 +- fs/xfs/utf8norm/Makefile | 37 + fs/xfs/utf8norm/mkutf8data.c | 3239 ++++++++++++++++++++++++++++++++++++++++++ fs/xfs/utf8norm/utf8norm.c | 649 +++++++++ fs/xfs/utf8norm/utf8norm.h | 116 ++
Quoted 3 lines
Again, nothing XFS specific here. It's being built as a separate module and the only thing that XFS uses are exported functions, so it really should be generic library code....
I'll get this moved to lib/ as you suggested elsewhere in the thread.
Thanks,
Ben
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 07/10] xfs: add trie generator and supporting code for UTF-8.
Quoted 2 lines · Ben Myers
I'll get this moved to
lib/as you suggested elsewhere in the thread.
Given that this is a host side tool it should be under scripts/
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 8/10 xfs: add xfs_nameops for utf8 and utf8+casefold.
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
The xfs_utf8_nameops use the nfkdi normalization when comparing filenames, and are installed if the utf8bit is set in the super block.
The xfs_utf8_ci_nameops use the nfkdicf normalization when comparing filenames, and are installed if both the utf8bit and the borgbit are set in the superblock.
Normalized filenames are not stored on disk. Normalization will fail if a filename is not valid UTF-8, in which case the filename is treated as an opaque blob.
---
[v2: updated to use utf8norm.ko module;
compiled conditionally on CONFIG_XFS_UTF8=y;
utf8version is now a function;
move xfs_utf8.[ch] into libxfs. --bpm]
---
fs/xfs/Makefile | 2 +
fs/xfs/libxfs/xfs_dir2.c | 24 ++++-
fs/xfs/libxfs/xfs_utf8.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++
fs/xfs/libxfs/xfs_utf8.h | 25 +++++
fs/xfs/xfs_iops.c | 2 +-
5 files changed, 290 insertions(+), 5 deletions(-)
create mode 100644 fs/xfs/libxfs/xfs_utf8.c
create mode 100644 fs/xfs/libxfs/xfs_utf8.hfs/xfs/Makefile +2 -0
@@ -114,6 +114,8 @@ xfs-$(CONFIG_XFS_QUOTA) += xfs_dquot.o \ xfs_qm.o \ xfs_quotaops.o +xfs-$(CONFIG_XFS_UTF8) += libxfs/xfs_utf8.o + # xfs_rtbitmap is shared with libxfs xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o
fs/xfs/libxfs/xfs_dir2.c +20 -4
@@ -35,6 +35,7 @@#include "xfs_error.h" #include "xfs_trace.h" #include "xfs_dinode.h" +#include "xfs_utf8.h" struct xfs_name xfs_name_dotdot = { (unsigned char *)".." ,2 ,XFS_DIR3_FT_DIR };
@@ -156,10 +157,25 @@ xfs_da_mount( (uint )sizeof (xfs_da_node_entry_t); dageo->magicpct = (dageo->blksize *37 ) /100 ; -if (xfs_sb_version_hasasciici (&mp->m_sb)) - mp->m_dirnameops = &xfs_ascii_ci_nameops; -else - mp->m_dirnameops = &xfs_default_nameops; +if (xfs_sb_version_hasutf8 (&mp->m_sb)) { +#ifdef CONFIG_XFS_UTF8 +if (xfs_sb_version_hasasciici (&mp->m_sb)) + mp->m_dirnameops = &xfs_utf8_ci_nameops; +else + mp->m_dirnameops = &xfs_utf8_nameops; +#else +xfs_warn (mp, +"Recompile XFS with CONFIG_XFS_UTF8 to mount this filesystem" ); +kmem_free (mp->m_dir_geo); +kmem_free (mp->m_attr_geo); +return -ENOSYS ; +#endif + }else { +if (xfs_sb_version_hasasciici (&mp->m_sb)) + mp->m_dirnameops = &xfs_ascii_ci_nameops; +else + mp->m_dirnameops = &xfs_default_nameops; + }return 0 ; }
fs/xfs/libxfs/xfs_utf8.c new file +242 -0
242 lines not on this page · raw message
fs/xfs/libxfs/xfs_utf8.h new file +25 -0
@@ -0,0 +1,25 @@ +/* +* Copyright (c) 2014 SGI. +* All rights reserved. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef XFS_UTF8_H +#define XFS_UTF8_H + +extern struct xfs_nameops xfs_utf8_nameops; +extern struct xfs_nameops xfs_utf8_ci_nameops; + +#endif /* XFS_UTF8_H */
fs/xfs/xfs_iops.c +1 -1
@@ -1257,7 +1257,7 @@ xfs_setup_inode(break ;case S_IFDIR :lockdep_set_class (&ip->i_lock.mr_lock, &xfs_dir_ilock_class); -if (xfs_sb_version_hasasciici (&XFS_M (inode->i_sb)->m_sb)) +if (xfs_sb_version_hasci (&XFS_M (inode->i_sb)->m_sb)) inode->i_op = &xfs_dir_ci_inode_operations;else inode->i_op = &xfs_dir_inode_operations;
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 9/10 xfs: apply utf-8 normalization rules to user extended attribute names
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Apply the same rules for UTF-8 normalization to the names of user-defined extended attributes. System attributes are excluded because they are not user-visible in the first place, and the kernel is expected to know what it is doing when naming them.
--- fs/xfs/libxfs/xfs_attr.c | 56 ++++++++++++++++++++++++++++++++++++------- fs/xfs/libxfs/xfs_attr_leaf.c | 11 +++++++-- fs/xfs/libxfs/xfs_utf8.c | 7 ++++++ fs/xfs/xfs_attr_list.c | 11 ++++++++- 4 files changed, 74 insertions(+), 11 deletions(-)
fs/xfs/libxfs/xfs_attr.c +48 -8
@@ -83,12 +83,14 @@ xfs_attr_args_init( const unsigned char *name, int flags) { +struct xfs_mount *mp = dp->i_mount; +int error;if (!name)return -EINVAL ;memset (args,0 ,sizeof (*args)); - args->geo = dp->i_mount->m_attr_geo; + args->geo = mp->m_attr_geo; args->whichfork =XFS_ATTR_FORK ; args->dp = dp; args->flags = flags;
@@ -97,7 +99,11 @@ xfs_attr_args_init(if (args->namelen >=MAXNAMELEN )return -EFAULT ;/* match IRIX behaviour */ - args->hashval =xfs_da_hashname (args->name, args->namelen); +if (!xfs_sb_version_hasutf8 (&mp->m_sb)) + args->hashval =xfs_da_hashname (args->name, args->namelen); +else if ((error = mp->m_dirnameops->normhash (args)) !=0 ) +return error; +return 0 ; }
@@ -154,6 +160,9 @@ xfs_attr_get( error =xfs_attr_node_get (&args);xfs_iunlock (ip, lock_mode); +if (args.norm) +kmem_free (args.norm); + *valuelenp = args.valuelen;return error == -EEXIST ?0 : error; }
@@ -216,8 +225,11 @@ xfs_attr_set(return -EIO ; error =xfs_attr_args_init (&args, dp, name, flags); -if (error) +if (error) { +if (args.norm) +kmem_free (args.norm);return error; + } args.value = value; args.valuelen = valuelen;
@@ -227,8 +239,11 @@ xfs_attr_set( args.total =xfs_attr_calc_size (&args, &local); error =xfs_qm_dqattach (dp,0 ); -if (error) +if (error) { +if (args.norm) +kmem_free (args.norm);return error; + }/* * If the inode doesn't have an attribute fork, add one.
@@ -239,8 +254,11 @@ xfs_attr_set(XFS_ATTR_SF_ENTSIZE_BYNAME (args.namelen, valuelen); error =xfs_bmap_add_attrfork (dp, sf_size, rsvd); -if (error) +if (error) { +if (args.norm) +kmem_free (args.norm);return error; + } }/*
@@ -270,6 +288,8 @@ xfs_attr_set( error =xfs_trans_reserve (args.trans, &tres, args.total,0 );if (error) {xfs_trans_cancel (args.trans,0 ); +if (args.norm) +kmem_free (args.norm);return error; }xfs_ilock (dp,XFS_ILOCK_EXCL );
@@ -280,6 +300,8 @@ xfs_attr_set(if (error) {xfs_iunlock (dp,XFS_ILOCK_EXCL );xfs_trans_cancel (args.trans,XFS_TRANS_RELEASE_LOG_RES ); +if (args.norm) +kmem_free (args.norm);return error; }
@@ -327,6 +349,8 @@ xfs_attr_set( XFS_TRANS_RELEASE_LOG_RES);xfs_iunlock (dp,XFS_ILOCK_EXCL ); +if (args.norm) +kmem_free (args.norm);return error ? error : err2; }
@@ -388,7 +412,8 @@ xfs_attr_set(xfs_trans_log_inode (args.trans, dp,XFS_ILOG_CORE ); error =xfs_trans_commit (args.trans,XFS_TRANS_RELEASE_LOG_RES );xfs_iunlock (dp,XFS_ILOCK_EXCL ); - +if (args.norm) +kmem_free (args.norm);return error; out:
@@ -397,6 +422,8 @@ out: XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); }xfs_iunlock (dp,XFS_ILOCK_EXCL ); +if (args.norm) +kmem_free (args.norm);return error; }
@@ -425,8 +452,11 @@ xfs_attr_remove(return -ENOATTR ; error =xfs_attr_args_init (&args, dp, name, flags); -if (error) +if (error) { +if (args.norm) +kmem_free (args.norm);return error; + } args.firstblock = &firstblock; args.flist = &flist;
@@ -439,8 +469,11 @@ xfs_attr_remove( args.op_flags =XFS_DA_OP_OKNOENT ; error =xfs_qm_dqattach (dp,0 ); -if (error) +if (error) { +if (args.norm) +kmem_free (args.norm);return error; + }/* * Start our first transaction of the day.
@@ -466,6 +499,8 @@ xfs_attr_remove( XFS_ATTRRM_SPACE_RES(mp), 0);if (error) {xfs_trans_cancel (args.trans,0 ); +if (args.norm) +kmem_free (args.norm);return error; }
@@ -506,6 +541,8 @@ xfs_attr_remove(xfs_trans_log_inode (args.trans, dp,XFS_ILOG_CORE ); error =xfs_trans_commit (args.trans,XFS_TRANS_RELEASE_LOG_RES );xfs_iunlock (dp,XFS_ILOCK_EXCL ); +if (args.norm) +kmem_free (args.norm);return error;
@@ -515,6 +552,9 @@ out: XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); }xfs_iunlock (dp,XFS_ILOCK_EXCL ); +if (args.norm) +kmem_free (args.norm); +return error; }
fs/xfs/libxfs/xfs_attr_leaf.c +9 -2
@@ -661,6 +661,7 @@ int xfs_attr_shortform_to_leaf(xfs_da_args_t *args) {xfs_inode_t *dp; +struct xfs_mount *mp;xfs_attr_shortform_t *sf;xfs_attr_sf_entry_t *sfe;xfs_da_args_t nargs;
@@ -673,6 +674,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)trace_xfs_attr_sf_to_leaf (args); dp = args->dp; + mp = dp->i_mount; ifp = dp->i_afp; sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; size =be16_to_cpu (sf->hdr.totsize);
@@ -726,13 +728,18 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args) nargs.namelen = sfe->namelen; nargs.value = &sfe->nameval[nargs.namelen]; nargs.valuelen = sfe->valuelen; - nargs.hashval =xfs_da_hashname (sfe->nameval, - sfe->namelen); nargs.flags =XFS_ATTR_NSP_ONDISK_TO_ARGS (sfe->flags); +if (!xfs_sb_version_hasutf8 (&mp->m_sb)) + nargs.hashval =xfs_da_hashname (sfe->nameval, + sfe->namelen); +else if ((error = mp->m_dirnameops->normhash (&nargs)) !=0 ) + goto out; error =xfs_attr3_leaf_lookup_int (bp, &nargs);/* set a->index */ ASSERT (error == -ENOATTR ); error =xfs_attr3_leaf_add (bp, &nargs);ASSERT (error != -ENOSPC ); +if (nargs.norm) +kmem_free (nargs.norm);if (error) goto out; sfe =XFS_ATTR_SF_NEXTENTRY (sfe);
fs/xfs/libxfs/xfs_utf8.c +7 -0
@@ -38,6 +38,7 @@#include "xfs_inode.h" #include "xfs_inode_item.h" #include "xfs_bmap.h" +#include "xfs_attr.h" #include "xfs_error.h" #include "xfs_trace.h" #include "xfs_utf8.h"
@@ -80,6 +81,9 @@ xfs_utf8_normhash(ssize_t normlen;int c; +/* Don't normalize system attribute names. */ +if (args->flags & (ATTR_ROOT |ATTR_SECURE )) + goto blob; nfkdi =utf8nfkdi (utf8version ());/* Failure to normalize is treated as a blob. */ if ((normlen =utf8nlen (nfkdi, args->name, args->namelen)) <0 )
@@ -179,6 +183,9 @@ xfs_utf8_ci_normhash(ssize_t normlen;int c; +/* Don't normalize system attribute names. */ +if (args->flags & (ATTR_ROOT |ATTR_SECURE )) + goto blob; nfkdicf =utf8nfkdicf (utf8version ());/* Failure to normalize is treated as a blob. */ if ((normlen =utf8nlen (nfkdicf, args->name, args->namelen)) <0 )
fs/xfs/xfs_attr_list.c +10 -1
@@ -76,12 +76,14 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)xfs_attr_shortform_t *sf;xfs_attr_sf_entry_t *sfe;xfs_inode_t *dp; +struct xfs_mount *mp;int sbsize, nsbuf, count, i;int error;ASSERT (context !=NULL ); dp = context->dp;ASSERT (dp !=NULL ); + mp = dp->i_mount;ASSERT (dp->i_afp !=NULL ); sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;ASSERT (sf !=NULL );
@@ -154,7 +156,14 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) } sbp->entno = i; - sbp->hash =xfs_da_hashname (sfe->nameval, sfe->namelen); +/* ATTR_ROOT and ATTR_SECURE are never normalized. */ +if (!xfs_sb_version_hasutf8 (&mp->m_sb) || + (sfe->flags & (ATTR_ROOT |ATTR_SECURE ))) { + sbp->hash =xfs_da_hashname (sfe->nameval, sfe->namelen); + }else { + sbp->hash = mp->m_dirnameops->hashname (sfe->nameval, + sfe->namelen); + } sbp->name = sfe->nameval; sbp->namelen = sfe->namelen;/* These are bytes, and both on-disk, don't endian-flip */
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 10/10 xfs: implement demand load of utf8norm.ko
In reply to Ben MyersFrom: Ben Myers <[email protected]>
The utf8 normalization module is large and there is no need to have it loaded unless an xfs filesystem with utf8 enabled has been mounted. This loads utf8norm.ko at mount time for filesystems that need it. This is optional on CONFIG_XFS_UTF8_DEMAND_LOAD.
--- fs/xfs/Kconfig | 10 +++++ fs/xfs/libxfs/xfs_dir2.c | 9 ++++ fs/xfs/libxfs/xfs_utf8.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_utf8.h | 5 +++ fs/xfs/xfs_super.c | 6 +++ 5 files changed, 134 insertions(+)
fs/xfs/Kconfig +10 -0
@@ -103,3 +103,13 @@ config XFS_UTF8 Say Y here to enable utf8 normalization support in XFS. You will be able to mount and use filesystems created with the utf8 mkfs.xfs option. + +config XFS_UTF8_DEMAND_LOAD + bool "XFS loads UTF-8 normalization module on demand" + depends on XFS_FS + depends on XFS_UTF8 + help + Say Y here to enable on demand loading of the utf8 + normalization module. This enables the large nomalization + module to remain unloaded until a filesystem with utf8 support + is mounted.
fs/xfs/libxfs/xfs_dir2.c +9 -0
@@ -35,7 +35,9 @@#include "xfs_error.h" #include "xfs_trace.h" #include "xfs_dinode.h" +#ifdef CONFIG_XFS_UTF8 #include "xfs_utf8.h" +#endif struct xfs_name xfs_name_dotdot = { (unsigned char *)".." ,2 ,XFS_DIR3_FT_DIR };
@@ -159,6 +161,13 @@ xfs_da_mount(if (xfs_sb_version_hasutf8 (&mp->m_sb)) {#ifdef CONFIG_XFS_UTF8 +#ifdef CONFIG_XFS_UTF8_DEMAND_LOAD +if (xfs_init_utf8_module (mp)) { +kmem_free (mp->m_dir_geo); +kmem_free (mp->m_attr_geo); +return -ENOSYS ; + } +#endif /* CONFIG_XFS_UTF8_DEMAND_LOAD */ if (xfs_sb_version_hasasciici (&mp->m_sb)) mp->m_dirnameops = &xfs_utf8_ci_nameops;else
fs/xfs/libxfs/xfs_utf8.c +104 -0
110 lines not on this page · raw message
fs/xfs/libxfs/xfs_utf8.h +5 -0
@@ -22,4 +22,9 @@extern struct xfs_nameops xfs_utf8_nameops;extern struct xfs_nameops xfs_utf8_ci_nameops; +#ifdef CONFIG_XFS_UTF8_DEMAND_LOAD +extern int xfs_init_utf8_module (struct xfs_mount *); +extern void xfs_put_utf8_module (void ); +#endif +#endif /* XFS_UTF8_H */
fs/xfs/xfs_super.c +6 -0
@@ -47,6 +47,9 @@#include "xfs_dinode.h" #include "xfs_filestream.h" #include "xfs_quota.h" +#ifdef CONFIG_XFS_UTF8_DEMAND_LOAD +#include "xfs_utf8.h" +#endif #include <linux/namei.h> #include <linux/init.h>
@@ -1809,6 +1812,9 @@ exit_xfs_fs(void)xfs_mru_cache_uninit ();xfs_destroy_workqueues ();xfs_destroy_zones (); +#ifdef CONFIG_XFS_UTF8_DEMAND_LOAD +xfs_put_utf8_module (); +#endif }module_init (init_xfs_fs);
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
cover xfsprogs: Unicode/UTF-8 support for XFS
In reply to Ben MyersHi,
Here is the xfsprogs portion of the Unicode/UTF-8 support. A number of the patches in libxfs correspond with kernel patches previously posted, and then there are patches to add support to mkfs, xfs_info, xfs_repair, and a test.
(Note that the Unicode character database files have also been removed here due to their size.)
Thanks,
Ben
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 1/13 libxfs: return the first match during case-insensitive lookup
From: Olaf Weber <[email protected]>
Change the XFS case-insensitive lookup code to return the first match found, even if it is not an exact match. Whether a filesystem uses case-insensitive lookups is determined by a superblock bit set during filesystem creation. This means that normal use cannot create two files that both match the same filename.
--- libxfs/xfs_dir2_block.c | 17 ++++------- libxfs/xfs_dir2_leaf.c | 38 ++++------------------- libxfs/xfs_dir2_node.c | 80 ++++++++++++++++++------------------------------- libxfs/xfs_dir2_sf.c | 8 ++--- 4 files changed, 44 insertions(+), 99 deletions(-)
libxfs/xfs_dir2_block.c +5 -12
@@ -705,28 +705,21 @@ xfs_dir2_block_lookup_int( dep = (xfs_dir2_data_entry_t *) ((char *)hdr +xfs_dir2_dataptr_to_off (mp, addr));/* -* Compare name and if it's an exact match, return the index -* and buffer. If it's the first case-insensitive match, store -* the index and buffer and continue looking for an exact match. +* Compare name and if it's a match, return the +* index and buffer. */ cmp = mp->m_dirnameops->compname (args, dep->name, dep->namelen); -if (cmp !=XFS_CMP_DIFFERENT && cmp != args->cmpresult) { +if (cmp !=XFS_CMP_DIFFERENT ) { args->cmpresult = cmp; *bpp = bp; *entno = mid; -if (cmp ==XFS_CMP_EXACT ) -return 0 ; +return 0 ; } }while (++mid <be32_to_cpu (btp->count) &&be32_to_cpu (blp[mid].hashval) == hash);ASSERT (args->op_flags &XFS_DA_OP_OKNOENT ); -/* -* Here, we can only be doing a lookup (not a rename or replace). -* If a case-insensitive match was found earlier, return success. -*/ -if (args->cmpresult ==XFS_CMP_CASE ) -return 0 ; +ASSERT (args->cmpresult ==XFS_CMP_DIFFERENT );/* * No match, release the buffer and return ENOENT. */
libxfs/xfs_dir2_leaf.c +6 -32
@@ -1246,7 +1246,6 @@ xfs_dir2_leaf_lookup_int(xfs_mount_t *mp;/* filesystem mount point */ xfs_dir2_db_t newdb;/* new data block number */ xfs_trans_t *tp;/* transaction pointer */ -xfs_dir2_db_t cidb =-1 ;/* case match data block no. */ enum xfs_dacmp cmp;/* name compare result */ struct xfs_dir2_leaf_entry *ents;struct xfs_dir3_icleaf_hdr leafhdr;
@@ -1307,47 +1306,22 @@ xfs_dir2_leaf_lookup_int( dep = (xfs_dir2_data_entry_t *)((char *)dbp->b_addr +xfs_dir2_dataptr_to_off (mp,be32_to_cpu (lep->address)));/* -* Compare name and if it's an exact match, return the index -* and buffer. If it's the first case-insensitive match, store -* the index and buffer and continue looking for an exact match. +* Compare name and if it's a match, return the index +* and buffer. */ cmp = mp->m_dirnameops->compname (args, dep->name, dep->namelen); -if (cmp !=XFS_CMP_DIFFERENT && cmp != args->cmpresult) { +if (cmp !=XFS_CMP_DIFFERENT ) { args->cmpresult = cmp; *indexp = index; -/* case exact match: return the current buffer. */ -if (cmp ==XFS_CMP_EXACT ) { - *dbpp = dbp; -return 0 ; - } - cidb = curdb; + *dbpp = dbp; +return 0 ; } }ASSERT (args->op_flags &XFS_DA_OP_OKNOENT ); -/* -* Here, we can only be doing a lookup (not a rename or remove). -* If a case-insensitive match was found earlier, re-read the -* appropriate data block if required and return it. -*/ -if (args->cmpresult ==XFS_CMP_CASE ) { -ASSERT (cidb !=-1 ); -if (cidb != curdb) { -xfs_trans_brelse (tp, dbp); - error =xfs_dir3_data_read (tp, dp, -xfs_dir2_db_to_da (mp, cidb), --1 , &dbp); -if (error) { -xfs_trans_brelse (tp, lbp); -return error; - } - } - *dbpp = dbp; -return 0 ; - } +ASSERT (args->cmpresult ==XFS_CMP_DIFFERENT );/* * No match found, return ENOENT. */ -ASSERT (cidb ==-1 );if (dbp)xfs_trans_brelse (tp, dbp);xfs_trans_brelse (tp, lbp);
libxfs/xfs_dir2_node.c +29 -51
121 lines not on this page · raw message
libxfs/xfs_dir2_sf.c +4 -4
@@ -833,13 +833,12 @@ xfs_dir2_sf_lookup(for (i =0 , sfep =xfs_dir2_sf_firstentry (sfp); i < sfp->count; i++, sfep =xfs_dir3_sf_nextentry (dp->i_mount, sfp, sfep)) {/* -* Compare name and if it's an exact match, return the inode -* number. If it's the first case-insensitive match, store the -* inode number and continue looking for an exact match. +* Compare name and if it's a match, return the inode +* number. */ cmp = dp->i_mount->m_dirnameops->compname (args, sfep->name, sfep->namelen); -if (cmp !=XFS_CMP_DIFFERENT && cmp != args->cmpresult) { +if (cmp !=XFS_CMP_DIFFERENT ) { args->cmpresult = cmp; args->inumber =xfs_dir3_sfe_get_ino (dp->i_mount, sfp, sfep);
@@ -848,6 +847,7 @@ xfs_dir2_sf_lookup(if (cmp ==XFS_CMP_EXACT )return XFS_ERROR (EEXIST ); ci_sfep = sfep; +break ; } }ASSERT (args->op_flags &XFS_DA_OP_OKNOENT );
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 2/13 libxfs: rename XFS_CMP_CASE to XFS_CMP_MATCH
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Rename XFS_CMP_CASE to XFS_CMP_MATCH. With unicode filenames and normalization, different strings will match on other criteria than case insensitivity.
--- include/xfs_da_btree.h | 2 +- libxfs/xfs_dir2.c | 9 ++++++--- libxfs/xfs_dir2_node.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-)
include/xfs_da_btree.h +1 -1
@@ -34,7 +34,7 @@ struct zone;enum xfs_dacmp {XFS_CMP_DIFFERENT ,/* names are completely different */ XFS_CMP_EXACT ,/* names are exactly the same */ -XFS_CMP_CASE /* names are same but differ in case */ +XFS_CMP_MATCH /* names are same but differ in encoding */ };/*
libxfs/xfs_dir2.c +6 -3
@@ -72,7 +72,7 @@ xfs_ascii_ci_compname(continue ;if (tolower (args->name[i]) !=tolower (name[i]))return XFS_CMP_DIFFERENT ; - result =XFS_CMP_CASE ; + result =XFS_CMP_MATCH ; }return result;
@@ -248,8 +248,11 @@ xfs_dir_cilookup_result( {if (args->cmpresult ==XFS_CMP_DIFFERENT )return ENOENT ; -if (args->cmpresult !=XFS_CMP_CASE || - !(args->op_flags &XFS_DA_OP_CILOOKUP )) +if (args->cmpresult ==XFS_CMP_EXACT ) +return EEXIST ; +ASSERT (args->cmpresult ==XFS_CMP_MATCH ); +/* Only dup the found name if XFS_DA_OP_CILOOKUP is set. */ +if (!(args->op_flags &XFS_DA_OP_CILOOKUP ))return EEXIST ; args->value =kmem_alloc (len,KM_NOFS |KM_MAYFAIL );
libxfs/xfs_dir2_node.c +1 -1
@@ -2034,7 +2034,7 @@ xfs_dir2_node_lookup( error =xfs_da3_node_lookup_int (state, &rval);if (error) rval = error; -else if (rval ==ENOENT && args->cmpresult ==XFS_CMP_CASE ) { +else if (rval ==ENOENT && args->cmpresult ==XFS_CMP_MATCH ) {/* If a CI match, dup the actual name and return EEXIST */ xfs_dir2_data_entry_t *dep;
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 3/13 libxfs: add xfs_nameops.normhash
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Add a normhash callout to the xfs_nameops. This callout takes an xfs_da_args structure as its argument, and calculates a hash value over the name. It may in the process create a normalized form of the name, and assign that to the norm/normlen fields in the xfs_da_args structure.
Changes:
The pointer in kmem_free() was type converted to suppress compiler warnings.
--- include/xfs_da_btree.h | 5 ++++- libxfs/xfs_da_btree.c | 9 ++++++++ libxfs/xfs_dir2.c | 56 +++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 57 insertions(+), 13 deletions(-)
include/xfs_da_btree.h +4 -1
@@ -42,7 +42,9 @@ enum xfs_dacmp {*/ typedef struct xfs_da_args { const __uint8_t *name; /* string (maybe not NULL terminated) */ - int namelen; /* length of string (maybe no NULL) */ + const __uint8_t *norm; /* normalized name (may be NULL) */ + int namelen; /* length of string (maybe no NULL) */ + int normlen; /* length of normalized name */ __uint8_t filetype; /* filetype of inode for directories */ __uint8_t *value; /* set of bytes (maybe contain NULLs) */ int valuelen; /* length of value */
@@ -131,6 +133,7 @@ typedef struct xfs_da_state {*/ struct xfs_nameops {xfs_dahash_t (*hashname)(struct xfs_name *); +int (*normhash)(struct xfs_da_args *);enum xfs_dacmp (*compname)(struct xfs_da_args *,const unsigned char *,int ); };
libxfs/xfs_da_btree.c +9 -0
@@ -2000,8 +2000,17 @@ xfs_default_hashname(return xfs_da_hashname (name->name, name->len); } +STATIC int +xfs_da_normhash ( +struct xfs_da_args *args) +{ + args->hashval =xfs_da_hashname (args->name, args->namelen); +return 0 ; +} +const struct xfs_nameops xfs_default_nameops = { .hashname = xfs_default_hashname, + .normhash = xfs_da_normhash, .compname = xfs_da_compname };
libxfs/xfs_dir2.c +44 -12
162 lines not on this page · raw message
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 4/13 libxfs: change interface of xfs_nameops.normhash
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
With the introduction of the xfs_nameops.normhash callout, all uses of the hashname callout now occur in places where an xfs_name structure must be explicitly created just to match the parameter passing convention of this callout. Change the arguments to a const unsigned char * and int instead.
--- db/check.c | 6 ++---- include/xfs_da_btree.h | 2 +- libxfs/xfs_da_btree.c | 9 +-------- libxfs/xfs_dir2.c | 10 ++++++---- libxfs/xfs_dir2_block.c | 5 +---- libxfs/xfs_dir2_data.c | 6 ++---- repair/phase6.c | 2 +- 7 files changed, 14 insertions(+), 26 deletions(-)
db/check.c +2 -4
@@ -2212,7 +2212,6 @@ process_data_dir_v2(int stale =0 ;int tag_err;__be16 *tagp; -struct xfs_name xname; data = iocur_top->data; block = iocur_top->data;
@@ -2323,9 +2322,8 @@ process_data_dir_v2( tag_err +=be16_to_cpu (*tagp) != (char *)dep - (char *)data; addr =xfs_dir2_db_off_to_dataptr (mp, db, (char *)dep - (char *)data); - xname.name = dep->name; - xname.len = dep->namelen; -dir_hash_add (mp->m_dirnameops->hashname (&xname), addr); +dir_hash_add (mp->m_dirnameops->hashname (dep->name, + dep->namelen), addr); ptr +=xfs_dir3_data_entsize (mp, dep->namelen); count++; lastfree =0 ;
include/xfs_da_btree.h +1 -1
@@ -132,7 +132,7 @@ typedef struct xfs_da_state {* Name ops for directory and/or attr name operations */ struct xfs_nameops { -xfs_dahash_t (*hashname)(struct xfs_name *); +xfs_dahash_t (*hashname)(const unsigned char *,int );int (*normhash)(struct xfs_da_args *);enum xfs_dacmp (*compname)(struct xfs_da_args *,const unsigned char *,int );
libxfs/xfs_da_btree.c +1 -8
@@ -1993,13 +1993,6 @@ xfs_da_compname( XFS_CMP_EXACT :XFS_CMP_DIFFERENT ; } -static xfs_dahash_t -xfs_default_hashname ( -struct xfs_name *name) -{ -return xfs_da_hashname (name->name, name->len); -} - STATIC intxfs_da_normhash (struct xfs_da_args *args)
@@ -2009,7 +2002,7 @@ xfs_da_normhash( }const struct xfs_nameops xfs_default_nameops = { - .hashname = xfs_default_hashname, + .hashname = xfs_da_hashname, .normhash = xfs_da_normhash, .compname = xfs_da_compname };
libxfs/xfs_dir2.c +6 -4
@@ -43,13 +43,14 @@ const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = {*/ STATIC xfs_dahash_txfs_ascii_ci_hashname ( -struct xfs_name *name) +const unsigned char *name, +int len) {xfs_dahash_t hash;int i; -for (i =0 , hash =0 ; i < name->len; i++) - hash =tolower (name->name[i]) ^rol32 (hash,7 ); +for (i =0 , hash =0 ; i < len; i++) + hash =tolower (name[i]) ^rol32 (hash,7 );return hash; }
@@ -475,7 +476,8 @@ xfs_dir_canenter( args.name = name->name; args.namelen = name->len; args.filetype = name->type; - args.hashval = dp->i_mount->m_dirnameops->hashname (name); + args.hashval = dp->i_mount->m_dirnameops->hashname (name->name, + name->len); args.dp = dp; args.whichfork =XFS_DATA_FORK ; args.trans = tp;
libxfs/xfs_dir2_block.c +1 -4
@@ -1047,7 +1047,6 @@ xfs_dir2_sf_to_block(xfs_dir2_sf_hdr_t *sfp;/* shortform header */ __be16 *tagp;/* end of data entry */ xfs_trans_t *tp;/* transaction pointer */ -struct xfs_name name;struct xfs_ifork *ifp;trace_xfs_dir2_sf_to_block (args);
@@ -1205,10 +1204,8 @@ xfs_dir2_sf_to_block( tagp =xfs_dir3_data_entry_tag_p (mp, dep); *tagp =cpu_to_be16 ((char *)dep - (char *)hdr);xfs_dir2_data_log_entry (tp, bp, dep); - name.name = sfep->name; - name.len = sfep->namelen; blp[2 + i].hashval =cpu_to_be32 (mp->m_dirnameops-> -hashname (&name)); +hashname (sfep->name, sfep->namelen)); blp[2 + i].address =cpu_to_be32 (xfs_dir2_byte_to_dataptr (mp, (char *)dep - (char *)hdr)); offset = (int )((char *)(tagp +1 ) - (char *)hdr);
libxfs/xfs_dir2_data.c +2 -4
@@ -46,7 +46,6 @@ __xfs_dir3_data_check(xfs_mount_t *mp;/* filesystem mount point */ char *p;/* current data position */ int stale;/* count of stale leaves */ -struct xfs_name name; mp = bp->b_target->bt_mount; hdr = bp->b_addr;
@@ -142,9 +141,8 @@ __xfs_dir3_data_check( addr =xfs_dir2_db_off_to_dataptr (mp, mp->m_dirdatablk, (xfs_dir2_data_aoff_t) ((char *)dep - (char *)hdr)); - name.name = dep->name; - name.len = dep->namelen; - hash = mp->m_dirnameops->hashname (&name); + hash = mp->m_dirnameops-> +hashname (dep->name, dep->namelen);for (i =0 ; i <be32_to_cpu (btp->count); i++) {if (be32_to_cpu (lep[i].address) == addr &&be32_to_cpu (lep[i].hashval) == hash)
repair/phase6.c +1 -1
@@ -195,7 +195,7 @@ dir_hash_add( dup =0 ;if (!junk) { - hash = mp->m_dirnameops->hashname (&xname); + hash = mp->m_dirnameops->hashname (name, namelen); byhash =DIR_HASH_FUNC (hashtab, hash);/*
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 5/13 libxfs: add a superblock feature bit to indicate UTF-8 support.
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
When UTF-8 support is enabled, the xfs_dir_ci_inode_operations must be installed. Add xfs_sb_version_hasci(), which tests both the borgbit and the utf8bit, and returns true if at least one of them is set. Replace calls to xfs_sb_version_hasasciici() as needed.
--- include/xfs_fs.h | 2 +- include/xfs_sb.h | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-)
include/xfs_fs.h +1 -1
@@ -239,7 +239,7 @@ typedef struct xfs_fsop_resblks {#define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000/* version 5 superblock */ #define XFS_FSOP_GEOM_FLAGS_FTYPE 0x10000/* inode directory types */ #define XFS_FSOP_GEOM_FLAGS_FINOBT 0x20000/* free inode btree */ - +#define XFS_FSOP_GEOM_FLAGS_UTF8 0x40000/* utf8 filenames */ /* * Minimum and maximum sizes need for growth checks.
include/xfs_sb.h +24 -1
@@ -82,6 +82,8 @@ struct xfs_trans;#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004#define XFS_SB_VERSION2_ATTR2BIT 0x00000008/* Inline attr rework */ #define XFS_SB_VERSION2_PARENTBIT 0x00000010/* parent pointers */ +#define XFS_SB_VERSION2_PARENTBIT 0x00000010/* parent pointers */ +#define XFS_SB_VERSION2_UTF8BIT 0x00000020/* utf8 names */ #define XFS_SB_VERSION2_PROJID32BIT 0x00000080/* 32 bit project id */ #define XFS_SB_VERSION2_CRCBIT 0x00000100/* metadata CRCs */ #define XFS_SB_VERSION2_FTYPE 0x00000200/* inode type in dir */
@@ -89,6 +91,7 @@ struct xfs_trans;#define XFS_SB_VERSION2_OKREALFBITS \ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \ XFS_SB_VERSION2_ATTR2BIT | \ + XFS_SB_VERSION2_UTF8BIT | \ XFS_SB_VERSION2_PROJID32BIT | \ XFS_SB_VERSION2_FTYPE)#define XFS_SB_VERSION2_OKSASHFBITS \
@@ -600,8 +603,10 @@ xfs_sb_has_ro_compat_feature( }#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0)/* filetype in dirent */ +#define XFS_SB_FEAT_INCOMPAT_UTF8 (1 << 1)/* utf-8 name support */ #define XFS_SB_FEAT_INCOMPAT_ALL \ - (XFS_SB_FEAT_INCOMPAT_FTYPE) + (XFS_SB_FEAT_INCOMPAT_FTYPE | \ + XFS_SB_FEAT_INCOMPAT_UTF8)#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL static inline bool
@@ -649,6 +654,24 @@ static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp) (sbp->sb_features_ro_compat &XFS_SB_FEAT_RO_COMPAT_FINOBT ); } +static inline int xfs_sb_version_hasutf8 (xfs_sb_t *sbp) +{ +return (XFS_SB_VERSION_NUM (sbp) ==XFS_SB_VERSION_5 && +xfs_sb_has_incompat_feature (sbp,XFS_SB_FEAT_INCOMPAT_UTF8 )) || + (xfs_sb_version_hasmorebits (sbp) && + (sbp->sb_features2 &XFS_SB_VERSION2_UTF8BIT )); +} + +/* +* Special case: there are a number of places where we need to test +* both the borgbit and the utf8bit, and take the same action if +* either of those is set. +*/ +static inline int xfs_sb_version_hasci (xfs_sb_t *sbp) +{ +return xfs_sb_version_hasasciici (sbp) ||xfs_sb_version_hasutf8 (sbp); +} +/* * end of superblock version macros */
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 6/13 xfsprogs: add unicode character database files
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Add files from the Unicode Character Database, version 7.0.0, to the source. A helper program that generates a trie used for normalization from these files is part of a separate commit.
---
[v2: removed large unicode files. download them as below. -bpm]
cd support/ucd-7.0.0
wget http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt
wget http://www.unicode.org/Public/7.0.0/ucd/DerivedAge.txt
wget http://www.unicode.org/Public/7.0.0/ucd/extracted/DerivedCombiningClass.txt
wget http://www.unicode.org/Public/7.0.0/ucd/DerivedCoreProperties.txt
wget http://www.unicode.org/Public/7.0.0/ucd/NormalizationCorrections.txt
wget http://www.unicode.org/Public/7.0.0/ucd/NormalizationTest.txt
wget http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt
--- support/ucd-7.0.0/README | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 support/ucd-7.0.0/README
support/ucd-7.0.0/README new file +33 -0
@@ -0,0 +1,33 @@ +The files in this directory are part of the Unicode Character Database +for version 7.0.0 of the Unicode standard. + +The full set of files can be found here: + + http://www.unicode.org/Public/7.0.0/ucd/ + +The latest released version of the UCD can be found here: + + http://www.unicode.org/Public/UCD/latest/ + +The files in this directory are identical, except that they have been +renamed with a suffix indicating the unicode version. + +Individual source links: + + http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt + http://www.unicode.org/Public/7.0.0/ucd/DerivedAge.txt + http://www.unicode.org/Public/7.0.0/ucd/extracted/DerivedCombiningClass.txt + http://www.unicode.org/Public/7.0.0/ucd/DerivedCoreProperties.txt + http://www.unicode.org/Public/7.0.0/ucd/NormalizationCorrections.txt + http://www.unicode.org/Public/7.0.0/ucd/NormalizationTest.txt + http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt + +md5sums + + 9a92b2bfe56c6719def926bab524fefd CaseFolding-7.0.0.txt + 07b8b1027eb824cf0835314e94f23d2e DerivedAge-7.0.0.txt + 90c3340b16821e2f2153acdbe6fc6180 DerivedCombiningClass-7.0.0.txt + c41c0601f808116f623de47110ed4f93 DerivedCoreProperties-7.0.0.txt + 522720ddfc150d8e63a2518634829bce NormalizationCorrections-7.0.0.txt + 1f35175eba4a2ad795db489f789ae352 NormalizationTest-7.0.0.txt + c8355655731d75e6a3de8c20d7e601ba UnicodeData-7.0.0.txt
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 7/13 libxfs: add trie generator and supporting code for UTF-8.
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
mkutf8data.c is the source for a program that generates utf8data.h, which contains the trie that utf8norm.c uses. The trie is generated from the Unicode 7.0.0 data files. The format of the utf8data[] table is described in utf8norm.c.
Supporting functions for UTF-8 normalization are in utf8norm.c with the header utf8norm.h. Two normalization forms are supported: nfkdi and nfkdicf.
nfkdi:
- Apply unicode normalization form NFKD.
- Remove any Default_Ignorable_Code_Point.
nfkdicf:
- Apply unicode normalization form NFKD.
- Remove any Default_Ignorable_Code_Point.
- Apply a full casefold (C + F).
For the purposes of the code, a string is valid UTF-8 if:
- The values encoded are 0x1..0x10FFFF.
- The surrogate codepoints 0xD800..0xDFFFF are not encoded.
- The shortest possible encoding is used for all values.
The supporting functions work on null-terminated strings (utf8 prefix) and on length-limited strings (utf8n prefix).
--- include/utf8norm.h | 111 ++ libxfs/utf8norm.c | 628 ++++++++++ support/mkutf8data.c | 3232 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 3971 insertions(+) create mode 100644 include/utf8norm.h create mode 100644 libxfs/utf8norm.c create mode 100644 support/mkutf8data.c
include/utf8norm.h new file +111 -0
@@ -0,0 +1,111 @@ +/* +* Copyright (c) 2014 SGI. +* All rights reserved. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef UTF8NORM_H +#define UTF8NORM_H + +/* An opaque type used to determine the normalization in use. */ +typedef const struct utf8data *utf8data_t ; + +/* Encoding a unicode version number as a single unsigned int. */ +#define UNICODE_MAJ_SHIFT (16) +#define UNICODE_MIN_SHIFT (8) + +#define UNICODE_AGE (MAJ ,MIN ,REV ) \ + (((unsigned int)(MAJ) << UNICODE_MAJ_SHIFT) | \ + ((unsigned int)(MIN) << UNICODE_MIN_SHIFT) | \ + ((unsigned int)(REV))) + +/* Highest unicode version supported by the data tables. */ +extern const unsigned int utf8version; + +/* +* Look for the correct utf8data_t for a unicode version. +* Returns NULL if the version requested is too new. +* +* Two normalization forms are supported: nfkdi and nfkdicf. +* +* nfkdi: +* - Apply unicode normalization form NFKD. +* - Remove any Default_Ignorable_Code_Point. +* +* nfkdicf: +* - Apply unicode normalization form NFKD. +* - Remove any Default_Ignorable_Code_Point. +* - Apply a full casefold (C + F). +*/ +extern utf8data_t utf8nfkdi (unsigned int ); +extern utf8data_t utf8nfkdicf (unsigned int ); + +/* +* Determine the maximum age of any unicode character in the string. +* Returns 0 if only unassigned code points are present. +* Returns -1 if the input is not valid UTF-8. +*/ +extern int utf8agemax (utf8data_t ,const char *); +extern int utf8nagemax (utf8data_t ,const char *,size_t ); + +/* +* Determine the minimum age of any unicode character in the string. +* Returns 0 if any unassigned code points are present. +* Returns -1 if the input is not valid UTF-8. +*/ +extern int utf8agemin (utf8data_t ,const char *); +extern int utf8nagemin (utf8data_t ,const char *,size_t ); + +/* +* Determine the length of the normalized from of the string, +* excluding any terminating NULL byte. +* Returns 0 if only ignorable code points are present. +* Returns -1 if the input is not valid UTF-8. +*/ +extern ssize_t utf8len (utf8data_t ,const char *); +extern ssize_t utf8nlen (utf8data_t ,const char *,size_t ); + +/* +* Cursor structure used by the normalizer. +*/ +struct utf8cursor { +utf8data_t data; +const char *s; +const char *p; +const char *ss; +const char *sp; +unsigned int len; +unsigned int slen; +short int ccc; +short int nccc; +}; + +/* +* Initialize a utf8cursor to normalize a string. +* Returns 0 on success. +* Returns -1 on failure. +*/ +extern int utf8cursor (struct utf8cursor *,utf8data_t ,const char *); +extern int utf8ncursor (struct utf8cursor *,utf8data_t ,const char *,size_t ); + +/* +* Get the next byte in the normalization. +* Returns a value > 0 && < 256 on success. +* Returns 0 when the end of the normalization is reached. +* Returns -1 if the string being normalized is not valid UTF-8. +*/ +extern int utf8byte (struct utf8cursor *); + +#endif /* UTF8NORM_H */
libxfs/utf8norm.c new file +628 -0
628 lines not on this page · raw message
support/mkutf8data.c new file +3232 -0
2,261 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Part of the diff is not shown here. View the raw message.
PATCH 8/13 libxfs: add xfs_nameops for utf8 and utf8+casefold.
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
The xfs_utf8_nameops use the nfkdi normalization when comparing filenames, and are installed if the utf8bit is set in the super block.
The xfs_utf8_ci_nameops use the nfkdicf normalization when comparing filenames, and are installed if both the utf8bit and the borgbit are set in the superblock.
Normalized filenames are not stored on disk. Normalization will fail if a filename is not valid UTF-8, in which case the filename is treated as an opaque blob.
Changes:
Type conversion to "(const char *)" added to utf8ncursor() and utf8nlen() calls.
--- Makefile | 2 +- include/libxfs.h | 1 + include/xfs_utf8.h | 25 ++++++ libxfs/Makefile | 4 +- libxfs/xfs_dir2.c | 15 +++- libxfs/xfs_utf8.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++++ support/Makefile | 24 ++++++ 7 files changed, 303 insertions(+), 6 deletions(-) create mode 100644 include/xfs_utf8.h create mode 100644 libxfs/xfs_utf8.c create mode 100644 support/Makefile
Makefile +1 -1
@@ -40,7 +40,7 @@ LDIRDIRT = $(SRCDIR) LDIRT += $(SRCTAR) endif -LIB_SUBDIRS = libxfs libxlog libxcmd libhandle libdisk +LIB_SUBDIRS = support libxfs libxlog libxcmd libhandle libdisk TOOL_SUBDIRS = copy db estimate fsck fsr growfs io logprint mkfs quota \ mdrestore repair rtcp m4 man doc po debian
include/libxfs.h +1 -0
@@ -59,6 +59,7 @@#include <xfs/xfs_btree_trace.h> #include <xfs/xfs_bmap.h> #include <xfs/xfs_trace.h> +#include <xfs_utf8.h> #ifndef ARRAY_SIZE
include/xfs_utf8.h new file +25 -0
@@ -0,0 +1,25 @@ +/* +* Copyright (c) 2014 SGI. +* All rights reserved. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef XFS_UTF8_H +#define XFS_UTF8_H + +extern struct xfs_nameops xfs_utf8_nameops; +extern struct xfs_nameops xfs_utf8_ci_nameops; + +#endif /* XFS_UTF8_H */
libxfs/Makefile +3 -1
@@ -14,6 +14,7 @@ HFILES = xfs.h init.h xfs_dir2_priv.h crc32defs.h crc32table.h CFILES = cache.c \ crc32.c \ init.c kmem.c logitem.c radix-tree.c rdwr.c trans.c util.c \ + utf8norm.c \ xfs_alloc.c \ xfs_alloc_btree.c \ xfs_attr.c \
@@ -38,7 +39,8 @@ CFILES = cache.c \ xfs_rtbitmap.c \ xfs_sb.c \ xfs_symlink_remote.c \ - xfs_trans_resv.c + xfs_trans_resv.c \ + xfs_utf8.c CFILES += $(PKG_PLATFORM).c PCFILES = darwin.c freebsd.c irix.c linux.c
libxfs/xfs_dir2.c +11 -4
@@ -123,10 +123,17 @@ xfs_dir_mount( (uint )sizeof (xfs_da_node_entry_t); mp->m_dir_magicpct = (mp->m_dirblksize *37 ) /100 ; -if (xfs_sb_version_hasasciici (&mp->m_sb)) - mp->m_dirnameops = &xfs_ascii_ci_nameops; -else - mp->m_dirnameops = &xfs_default_nameops; +if (xfs_sb_version_hasutf8 (&mp->m_sb)) { +if (xfs_sb_version_hasasciici (&mp->m_sb)) + mp->m_dirnameops = &xfs_utf8_ci_nameops; +else + mp->m_dirnameops = &xfs_utf8_nameops; + }else { +if (xfs_sb_version_hasasciici (&mp->m_sb)) + mp->m_dirnameops = &xfs_ascii_ci_nameops; +else + mp->m_dirnameops = &xfs_default_nameops; + } }/*
libxfs/xfs_utf8.c new file +238 -0
238 lines not on this page · raw message
support/Makefile new file +24 -0
@@ -0,0 +1,24 @@ +# +# Copyright (c) 2014 SGI. All Rights Reserved. +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +default = ../include/utf8data.h + +../include/utf8data.h: mkutf8data.c + cc -o mkutf8data mkutf8data.c + cd ucd-7.0.0 ; ../mkutf8data + mv ucd-7.0.0/utf8data.h ../include + +default clean: + rm -f mkutf8data ../include/utf8data.h + +default install: + +default install-dev: + +default install-qa: + +-include .ltdep
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 9/13 libxfs: apply utf-8 normalization rules to user extended attribute names
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Apply the same rules for UTF-8 normalization to the names of user-defined extended attributes. System attributes are excluded because they are not user-visible in the first place, and the kernel is expected to know what it is doing when naming them.
--- libxfs/xfs_attr.c | 49 +++++++++++++++++++++++++++++++++++++++++-------- libxfs/xfs_attr_leaf.c | 11 +++++++++-- libxfs/xfs_utf8.c | 7 +++++++ 3 files changed, 57 insertions(+), 10 deletions(-)
libxfs/xfs_attr.c +41 -8
@@ -88,8 +88,9 @@ xfs_attr_get_int( int *valuelenp, int flags) { -xfs_da_args_t args; -int error; +xfs_da_args_t args; +struct xfs_mount *mp = ip->i_mount; +int error;if (!xfs_inode_hasattr (ip))return ENOATTR ;
@@ -103,9 +104,12 @@ xfs_attr_get_int( args.value = value; args.valuelen = *valuelenp; args.flags = flags; - args.hashval =xfs_da_hashname (args.name, args.namelen); args.dp = ip; args.whichfork =XFS_ATTR_FORK ; +if (!xfs_sb_version_hasutf8 (&mp->m_sb)) + args.hashval =xfs_da_hashname (args.name, args.namelen); +else if ((error = mp->m_dirnameops->normhash (&args)) !=0 ) +return error;/* * Decide on what work routines to call based on the inode size.
@@ -118,6 +122,9 @@ xfs_attr_get_int( error =xfs_attr_node_get (&args); } +if (args.norm) +kmem_free ((void *)args.norm); +/* * Return the number of bytes in the value to the caller. */
@@ -239,12 +246,15 @@ xfs_attr_set_int( args.value = value; args.valuelen = valuelen; args.flags = flags; - args.hashval =xfs_da_hashname (args.name, args.namelen); args.dp = dp; args.firstblock = &firstblock; args.flist = &flist; args.whichfork =XFS_ATTR_FORK ; args.op_flags =XFS_DA_OP_ADDNAME |XFS_DA_OP_OKNOENT ; +if (!xfs_sb_version_hasutf8 (&mp->m_sb)) + args.hashval =xfs_da_hashname (args.name, args.namelen); +else if ((error = mp->m_dirnameops->normhash (&args)) !=0 ) +return error;/* Size is now blocks for attribute data */ args.total =xfs_attr_calc_size (dp, name->len, valuelen, &local);
@@ -276,6 +286,8 @@ xfs_attr_set_int( error =xfs_trans_reserve (args.trans, &tres, args.total,0 );if (error) {xfs_trans_cancel (args.trans,0 ); +if (args.norm) +kmem_free ((void *)args.norm);return (error); }xfs_ilock (dp,XFS_ILOCK_EXCL );
@@ -286,6 +298,8 @@ xfs_attr_set_int(if (error) {xfs_iunlock (dp,XFS_ILOCK_EXCL );xfs_trans_cancel (args.trans,XFS_TRANS_RELEASE_LOG_RES ); +if (args.norm) +kmem_free ((void *)args.norm);return (error); }
@@ -333,7 +347,8 @@ xfs_attr_set_int( err2 =xfs_trans_commit (args.trans,XFS_TRANS_RELEASE_LOG_RES );xfs_iunlock (dp,XFS_ILOCK_EXCL ); - +if (args.norm) +kmem_free ((void *)args.norm);return (error ==0 ? err2 : error); }
@@ -398,6 +413,8 @@ xfs_attr_set_int(xfs_trans_log_inode (args.trans, dp,XFS_ILOG_CORE ); error =xfs_trans_commit (args.trans,XFS_TRANS_RELEASE_LOG_RES );xfs_iunlock (dp,XFS_ILOCK_EXCL ); +if (args.norm) +kmem_free ((void *)args.norm);return (error);
@@ -406,6 +423,9 @@ out:xfs_trans_cancel (args.trans,XFS_TRANS_RELEASE_LOG_RES |XFS_TRANS_ABORT );xfs_iunlock (dp,XFS_ILOCK_EXCL ); +if (args.norm) +kmem_free ((void *)args.norm); +return (error); }
@@ -452,12 +472,15 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags) args.name = name->name; args.namelen = name->len; args.flags = flags; - args.hashval =xfs_da_hashname (args.name, args.namelen); args.dp = dp; args.firstblock = &firstblock; args.flist = &flist; args.total =0 ; args.whichfork =XFS_ATTR_FORK ; +if (!xfs_sb_version_hasutf8 (&mp->m_sb)) + args.hashval =xfs_da_hashname (args.name, args.namelen); +else if ((error = mp->m_dirnameops->normhash (&args)) !=0 ) +return error;/* * we have no control over the attribute names that userspace passes us
@@ -470,8 +493,11 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)* Attach the dquots to the inode. */ error =xfs_qm_dqattach (dp,0 ); -if (error) -return error; +if (error) { +if (args.norm) +kmem_free ((void *)args.norm); +return error; + }/* * Start our first transaction of the day.
@@ -497,6 +523,8 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags) XFS_ATTRRM_SPACE_RES(mp), 0);if (error) {xfs_trans_cancel (args.trans,0 ); +if (args.norm) +kmem_free ((void *)args.norm);return (error); }
@@ -546,6 +574,8 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)xfs_trans_log_inode (args.trans, dp,XFS_ILOG_CORE ); error =xfs_trans_commit (args.trans,XFS_TRANS_RELEASE_LOG_RES );xfs_iunlock (dp,XFS_ILOCK_EXCL ); +if (args.norm) +kmem_free ((void *)args.norm);return (error);
@@ -554,6 +584,9 @@ out:xfs_trans_cancel (args.trans,XFS_TRANS_RELEASE_LOG_RES |XFS_TRANS_ABORT );xfs_iunlock (dp,XFS_ILOCK_EXCL ); +if (args.norm) +kmem_free ((void *)args.norm); +return (error); }
libxfs/xfs_attr_leaf.c +9 -2
@@ -634,6 +634,7 @@ int xfs_attr_shortform_to_leaf(xfs_da_args_t *args) {xfs_inode_t *dp; +struct xfs_mount *mp;xfs_attr_shortform_t *sf;xfs_attr_sf_entry_t *sfe;xfs_da_args_t nargs;
@@ -646,6 +647,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)trace_xfs_attr_sf_to_leaf (args); dp = args->dp; + mp = dp->i_mount; ifp = dp->i_afp; sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; size =be16_to_cpu (sf->hdr.totsize);
@@ -698,13 +700,18 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args) nargs.namelen = sfe->namelen; nargs.value = &sfe->nameval[nargs.namelen]; nargs.valuelen = sfe->valuelen; - nargs.hashval =xfs_da_hashname (sfe->nameval, - sfe->namelen); nargs.flags =XFS_ATTR_NSP_ONDISK_TO_ARGS (sfe->flags); +if (!xfs_sb_version_hasutf8 (&mp->m_sb)) + nargs.hashval =xfs_da_hashname (sfe->nameval, + sfe->namelen); +else if ((error = mp->m_dirnameops->normhash (&nargs)) !=0 ) + goto out; error =xfs_attr3_leaf_lookup_int (bp, &nargs);/* set a->index */ ASSERT (error ==ENOATTR ); error =xfs_attr3_leaf_add (bp, &nargs);ASSERT (error !=ENOSPC ); +if (nargs.norm) +kmem_free ((void *)nargs.norm);if (error) goto out; sfe =XFS_ATTR_SF_NEXTENTRY (sfe);
libxfs/xfs_utf8.c +7 -0
@@ -31,6 +31,7 @@#include "xfs_inode_fork.h" #include "xfs_bmap.h" #include "xfs_dir2.h" +#include "xfs_attr_leaf.h" #include "xfs_trace.h" #include "xfs_utf8.h" #include "utf8norm.h"
@@ -72,6 +73,9 @@ xfs_utf8_normhash(ssize_t normlen;int c; +/* Don't normalize system attribute names. */ +if (args->flags & (ATTR_ROOT |ATTR_SECURE )) + goto blob; nfkdi =utf8nfkdi (utf8version);/* Failure to normalize is treated as a blob. */ if ((normlen = utf8nlen(nfkdi, (const char *)args->name,
@@ -173,6 +177,9 @@ xfs_utf8_ci_normhash(ssize_t normlen;int c; +/* Don't normalize system attribute names. */ +if (args->flags & (ATTR_ROOT |ATTR_SECURE )) + goto blob; nfkdicf =utf8nfkdicf (utf8version);/* Failure to normalize is treated as a blob. */ if ((normlen = utf8nlen(nfkdicf, (const char *)args->name,
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 10/13 xfsprogs: add utf8 support to growfs
In reply to Ben MyersFrom: Mark Tinguely <[email protected]>
Add reporting of the utf-8 mkfs options to xfs_growfs and xfs_info.
--- growfs/xfs_growfs.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
growfs/xfs_growfs.c +8 -5
@@ -57,7 +57,8 @@ report_info( int crcs_enabled, int cimode, int ftype_enabled, - int finobt_enabled) + int finobt_enabled, + int utf8) { printf(_("meta-data=%-22s isize=%-6u agcount=%u, agsize=%u blks\n"
@@ -65,7 +66,7 @@ report_info(" =%-22s crc=%-8u finobt=%u\n" "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" -"naming =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n" +"naming =version %-14u bsize=%-6u ascii-ci=%d ftype=%d utf8=%d\n" "log =%-22s bsize=%-6u blocks=%u, version=%u\n" " =%-22s sectsz=%-5u sunit=%u blks, lazy-count=%u\n" "realtime =%-22s extsz=%-6u blocks=%llu, rtextents=%llu\n"),
@@ -76,7 +77,7 @@ report_info("" , geo.blocksize, (unsigned long long )geo.datablocks, geo.imaxpct,"" , geo.sunit, geo.swidth, - dirversion, geo.dirblocksize, cimode, ftype_enabled, + dirversion, geo.dirblocksize, cimode, ftype_enabled, utf8, isint ?_ ("internal" ) : logname ? logname :_ ("external" ), geo.blocksize, geo.logblocks, logversion, "", geo.logsectsize, geo.logsunit / geo.blocksize, lazycount,
@@ -114,6 +115,7 @@ main(int argc, char **argv)long long rsize;/* new rt size in fs blocks */ int ci;/* ASCII case-insensitive fs */ int lazycount;/* lazy superblock counters */ +int utf8;/* Unicode chars supported */ int xflag;/* -x flag */ char *fname;/* mount point name */ char *datadev;/* data device name */
@@ -247,11 +249,12 @@ main(int argc, char **argv) crcs_enabled = geo.flags &XFS_FSOP_GEOM_FLAGS_V5SB ?1 :0 ; ftype_enabled = geo.flags &XFS_FSOP_GEOM_FLAGS_FTYPE ?1 :0 ; finobt_enabled = geo.flags &XFS_FSOP_GEOM_FLAGS_FINOBT ?1 :0 ; + utf8 = geo.flags &XFS_FSOP_GEOM_FLAGS_UTF8 ?1 :0 ;if (nflag) {report_info (geo, datadev, isint, logdev, rtdev, lazycount, dirversion, logversion, attrversion, projid32bit, crcs_enabled, ci, - ftype_enabled, finobt_enabled); + ftype_enabled, finobt_enabled, utf8);exit (0 ); }
@@ -289,7 +292,7 @@ main(int argc, char **argv)report_info (geo, datadev, isint, logdev, rtdev, lazycount, dirversion, logversion, attrversion, projid32bit, crcs_enabled, ci, ftype_enabled, - finobt_enabled); + finobt_enabled, utf8); ddsize = xi.dsize; dlsize = ( xi.logBBsize? xi.logBBsize :
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 11/13 xfsprogs: add utf8 support to mkfs.xfs
In reply to Ben MyersFrom: Mark Tinguely <[email protected]>
Set the utf-8 feature bit.
--- man/man8/mkfs.xfs.8 | 9 ++++++++- mkfs/xfs_mkfs.c | 27 ++++++++++++++++++++++----- mkfs/xfs_mkfs.h | 3 ++- 3 files changed, 32 insertions(+), 7 deletions(-)
man/man8/mkfs.xfs.8 +8 -1
@@ -558,7 +558,7 @@ any power of 2 size from the filesystem block size up to 65536. .IP The .B version=ci -option enables ASCII only case-insensitive filename lookup and version +option enables ASCII or UTF-8 case-insensitive filename lookup and version 2 directories. Filenames are case-preserving, that is, the names are stored in directories using the case they were created with. .IP
@@ -582,6 +582,13 @@ When CRCs are enabled via the ftype functionality is always enabled. This feature can not be turned off for such filesystem configurations. .IP +.TP +.BI utf8[= value ] +This is used to enable the UTF-8 character set support. The +.I value +is either 0 or 1, with 1 signifying that UTF-8 character support is to be +enabled. If the value is omitted, 1 is assumed. +.IP .RE .TP .BI \-p " protofile"
mkfs/xfs_mkfs.c +22 -5
@@ -149,6 +149,8 @@ char *nopts[] = { "version",#define N_FTYPE 3 "ftype", +#define N_UTF8 4 +"utf8" , NULL, };
@@ -958,6 +960,7 @@ main(int nsflag;int nvflag;int nci; +int utf8;int Nflag;int discard =1 ;char *p;
@@ -1004,6 +1007,7 @@ main( logagno = logblocks = rtblocks = rtextblocks =0 ; Nflag = nlflag = nsflag = nvflag = nci =0 ; nftype = dirftype =0 ;/* inode type information in the dir */ + utf8 =0 ;/* utf-8 support */ dirblocklog = dirblocksize =0 ; dirversion =XFS_DFL_DIR_VERSION ; qflag =0 ;
@@ -1565,7 +1569,8 @@ _("cannot specify both crc and ftype\n"));if (nvflag)respec ('n' , nopts,N_VERSION );if (!strcasecmp (value,"ci" )) { - nci =1 ;/* ASCII CI mode */ +/* ASCII or UTF-8 CI mode */ + nci =1 ; }else { dirversion =atoi (value);if (dirversion !=2 )
@@ -1587,6 +1592,14 @@ _("cannot specify both crc and ftype\n")); } nftype =1 ;break ; +case N_UTF8 : +if (!value || *value =='\0' ) + value ="1" ; + c =atoi (value); +if (c <0 || c >1 ) +illegal (value,"n utf8" ); + utf8 = c; +break ;default :unknown ('n' , value); }
@@ -2460,7 +2473,8 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),*/ sbp->sb_features2 =XFS_SB_VERSION2_MKFS (crcs_enabled, lazy_sb_counters, attrversion ==2 , !projid16bit,0 , - (!crcs_enabled && dirftype)); + (!crcs_enabled && dirftype), + (!crcs_enabled && utf8)); sbp->sb_versionnum = XFS_SB_VERSION_MKFS(crcs_enabled, iaflag, dsunit != 0, logversion == 2, attrversion == 1,
@@ -2534,6 +2548,9 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),if (crcs_enabled) { sbp->sb_features_incompat =XFS_SB_FEAT_INCOMPAT_FTYPE ; dirftype =1 ; +/* turn on the utf-8 support */ +if (utf8) + sbp->sb_features_incompat |=XFS_SB_FEAT_INCOMPAT_UTF8 ; }if (!qflag || Nflag) {
@@ -2543,7 +2560,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n")," =%-22s crc=%-8u finobt=%u\n" "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" -"naming =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n" +"naming =version %-14u bsize=%-6u ascii-ci=%d ftype=%d utf8=%d\n" "log =%-22s bsize=%-6d blocks=%lld, version=%d\n" " =%-22s sectsz=%-5u sunit=%d blks, lazy-count=%d\n" "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n"),
@@ -2552,7 +2569,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),"" , crcs_enabled, finobt,"" , blocksize, (long long )dblocks, imaxpct,"" , dsunit, dswidth, - dirversion, dirblocksize, nci, dirftype, + dirversion, dirblocksize, nci, dirftype, utf8, logfile,1 << blocklog, (long long )logblocks, logversion,"" , lsectorsize, lsunit, lazy_sb_counters, rtfile, rtextblocks << blocklog,
@@ -3171,7 +3188,7 @@ usage( void ) sunit=value|su=num,sectlog=n|sectsize=num,\n\ lazy-count=0|1]\n\ /* label */ [-L label (maximum 12 characters)]\n\ -/* naming */ [-n log=n|size=num,version=2|ci,ftype=0|1]\n\ +/* naming */ [-n log=n|size=num,version=2|ci,ftype=0|1,utf8=0|1]\n\ /* no-op info only */ [-N]\n\ /* prototype file */ [-p fname]\n\ /* quiet */ [-q]\n\
mkfs/xfs_mkfs.h +2 -1
@@ -37,13 +37,14 @@ 0 ) : XFS_SB_VERSION_1 )#define XFS_SB_VERSION2_MKFS (crc, lazycount, attr2, projid32bit, parent, \ - ftype) (\ + ftype, utf8) (\ ((lazycount) ? XFS_SB_VERSION2_LAZYSBCOUNTBIT : 0) | \ ((attr2) ? XFS_SB_VERSION2_ATTR2BIT : 0) | \ ((projid32bit) ? XFS_SB_VERSION2_PROJID32BIT : 0) | \ ((parent) ? XFS_SB_VERSION2_PARENTBIT : 0) | \ ((crc) ? XFS_SB_VERSION2_CRCBIT : 0) | \ ((ftype) ? XFS_SB_VERSION2_FTYPE : 0) | \ + ((utf8) ? XFS_SB_VERSION2_UTF8BIT : 0) | \ 0 )#define XFS_DFL_BLOCKSIZE_LOG 12/* 4096 byte blocks */
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 12/13 xfsprogs: add utf8 support to xfs_repair
In reply to Ben MyersFrom: Mark Tinguely <[email protected]>
Fix the duplicate filename detection to use the utf-8 normalization routines.
--- repair/phase6.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-)
repair/phase6.c +25 -10
@@ -176,13 +176,15 @@ dir_hash_add(unsigned char *name, __uint8_t ftype) { -xfs_dahash_t hash =0 ; int byaddr;int byhash =0 ;dir_hash_ent_t *p;int dup;short junk;struct xfs_name xname; +xfs_da_args_t args; + +memset (&args,0 ,sizeof (xfs_da_args_t));ASSERT (!hashtab->names_duped);
@@ -195,19 +197,30 @@ dir_hash_add( dup =0 ;if (!junk) { - hash = mp->m_dirnameops->hashname (name, namelen); - byhash =DIR_HASH_FUNC (hashtab, hash); +int error; + + args.name = name; + args.namelen = namelen; + args.inumber = inum; + args.whichfork =XFS_DATA_FORK ; + + error = mp->m_dirnameops->normhash (&args); +if (error) +do_error (_ ("normalize has failed %d)\n" ), error); + + byhash =DIR_HASH_FUNC (hashtab, args.hashval);/* * search hash bucket for existing name. */ for (p = hashtab->byhash[byhash]; p; p = p->nextbyhash) { -if (p->hashval == hash && p->name.len == namelen) { -if (memcmp (p->name.name, name, namelen) ==0 ) { - dup =1 ; - junk =1 ; -break ; - } +if (p->hashval == args.hashval && + mp->m_dirnameops->compname (&args, p->name.name, + p->name.len) != +XFS_CMP_DIFFERENT ) { + dup =1 ; + junk =1 ; +break ; } } }
@@ -226,7 +239,7 @@ dir_hash_add( hashtab->last = p;if (!(p->junkit = junk)) { - p->hashval = hash; + p->hashval = args.hashval; p->nextbyhash = hashtab->byhash[byhash]; hashtab->byhash[byhash] = p; }
@@ -235,6 +248,8 @@ dir_hash_add( p->seen =0 ; p->name = xname; +if (args.norm) +kmem_free ((void *) args.norm);return !dup; }
Signature · 1 line
1.7.12.4
PATCH 13/13 xfsprogs: add a preliminary test for utf8 support
In reply to Ben MyersFrom: Ben Myers <[email protected]>
Here's a preliminary test for utf8 support in xfs. It is based on code that also does some testing in the trie generator. Here too we are using the NormalizationTest.txt file from the unicode distribution. We check that the normalization in libxfs is working and then run checks on a filesystem. Note that there are some 'blacklisted' unichars which normalize to reserved characters.
FIXME:
For convenience of build this patch is against xfsprogs access to libxfs. Handling of ignorables and case fold is also not implemented here.
--- Makefile | 2 +- chkutf8data/Makefile | 21 +++ chkutf8data/chkutf8data.c | 430 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 452 insertions(+), 1 deletion(-) create mode 100644 chkutf8data/Makefile create mode 100644 chkutf8data/chkutf8data.c
Makefile +1 -1
@@ -42,7 +42,7 @@ endif LIB_SUBDIRS = support libxfs libxlog libxcmd libhandle libdisk TOOL_SUBDIRS = copy db estimate fsck fsr growfs io logprint mkfs quota \ - mdrestore repair rtcp m4 man doc po debian + mdrestore repair rtcp m4 man doc po debian chkutf8data SUBDIRS = include $(LIB_SUBDIRS) $(TOOL_SUBDIRS)
chkutf8data/Makefile new file +21 -0
@@ -0,0 +1,21 @@ +# +# Copyright (c) 2014 SGI. All Rights Reserved. +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LTCOMMAND = chkutf8data +CFILES = chkutf8data.c + +LLDLIBS = $(LIBXFS) +LTDEPENDENCIES = $(LIBXFS) +LLDFLAGS = -static + +default: depend $(LTCOMMAND) + +include $(BUILDRULES) + +install: default + +-include .ltdep
chkutf8data/chkutf8data.c new file +430 -0
430 lines not on this page · raw message
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH 1/1 xfsprogs: add trie generator for UTF-8.
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
mkutf8data.c is the source for a program that generates utf8data.h, which contains the trie that utf8norm.c uses. The trie is generated from the Unicode 7.0.0 data files. The format of the utf8data[] table is described in utf8norm.c, which is added in the next patch.
--- Makefile | 2 +- support/Makefile | 24 + support/mkutf8data.c | 3232 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 3257 insertions(+), 1 deletion(-) create mode 100644 support/Makefile create mode 100644 support/mkutf8data.c
Makefile +1 -1
@@ -40,7 +40,7 @@ LDIRDIRT = $(SRCDIR) LDIRT += $(SRCTAR) endif -LIB_SUBDIRS = libxfs libxlog libxcmd libhandle libdisk +LIB_SUBDIRS = support libxfs libxlog libxcmd libhandle libdisk TOOL_SUBDIRS = copy db estimate fsck fsr growfs io logprint mkfs quota \ mdrestore repair rtcp m4 man doc po debian
support/Makefile new file +24 -0
@@ -0,0 +1,24 @@ +# +# Copyright (c) 2014 SGI. All Rights Reserved. +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +default = ../include/utf8data.h + +../include/utf8data.h: mkutf8data.c + cc -o mkutf8data mkutf8data.c + cd ucd-7.0.0 ; ../mkutf8data + mv ucd-7.0.0/utf8data.h ../include + +default clean: + rm -f mkutf8data ../include/utf8data.h + +default install: + +default install-dev: + +default install-qa: + +-include .ltdep
support/mkutf8data.c new file +3232 -0
2,968 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Part of the diff is not shown here. View the raw message.
Re: [PATCH 07a/13] xfsprogs: add trie generator for UTF-8.
support/mkutf8data.c line 38
Quoted 7 lines · Ben Myers
support/mkutf8data.c new file +7
-0+#define AGE_NAME "DerivedAge.txt" +#define CCC_NAME "DerivedCombiningClass.txt" +#define PROP_NAME "DerivedCoreProperties.txt" +#define DATA_NAME "UnicodeData.txt" +#define FOLD_NAME "CaseFolding.txt" +#define NORM_NAME "NormalizationCorrections.txt" +#define TEST_NAME "NormalizationTest.txt"
Is there a reason why you're using multiple text-based data files (and hand-parsing them) when there's an xml formatted flat file available ?
http://www.unicode.org/Public/UCD/latest/ucdxml/
And a 2nd question - why does the trie need to encode "the the unicode version in which the codepoint was assigned an interpretation" ?
Signature · 6 lines
Roger Willcocks <[email protected]> _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 07a/13] xfsprogs: add trie generator for UTF-8.
Hi Roger,
Quoted 12 lines · Roger Willcocks
support/mkutf8data.c line 38
Quoted 7 lines · Ben Myers
support/mkutf8data.c new file +7
-0+#define AGE_NAME "DerivedAge.txt" +#define CCC_NAME "DerivedCombiningClass.txt" +#define PROP_NAME "DerivedCoreProperties.txt" +#define DATA_NAME "UnicodeData.txt" +#define FOLD_NAME "CaseFolding.txt" +#define NORM_NAME "NormalizationCorrections.txt" +#define TEST_NAME "NormalizationTest.txt"Is there a reason why you're using multiple text-based data files (and hand-parsing them) when there's an xml formatted flat file available ?
Quoted 1 line
The UCD files being parsed are the authoritative source. Check out ucdxml.readme.txt.
Quoted 2 lines
And a 2nd question - why does the trie need to encode "the the unicode version in which the codepoint was assigned an interpretation" ?
You need to know whether a given code point is assigned in the version of Unicode you're normalizing for. Unicode 8 is supposed to release June/July 2015 (see http://www.unicode.org/versions/), but filesystems you created this year will still need the version 7 normalization. There is still some plumbing to do to pass the version along with the string for normalization.
I think you bring up a good point, but we'll need to support multiple versions in the long run.
Regards,
Ben
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 1/1 libxfs: add supporting code for UTF-8.
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Supporting functions for UTF-8 normalization are in utf8norm.c with the header utf8norm.h. Two normalization forms are supported: nfkdi and nfkdicf.
nfkdi:
- Apply unicode normalization form NFKD.
- Remove any Default_Ignorable_Code_Point.
nfkdicf:
- Apply unicode normalization form NFKD.
- Remove any Default_Ignorable_Code_Point.
- Apply a full casefold (C + F).
For the purposes of the code, a string is valid UTF-8 if:
- The values encoded are 0x1..0x10FFFF.
- The surrogate codepoints 0xD800..0xDFFFF are not encoded.
- The shortest possible encoding is used for all values.
The supporting functions work on null-terminated strings (utf8 prefix) and on length-limited strings (utf8n prefix).
--- include/utf8norm.h | 111 ++++++++++ libxfs/Makefile | 1 + libxfs/utf8norm.c | 628 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 740 insertions(+) create mode 100644 include/utf8norm.h create mode 100644 libxfs/utf8norm.c
include/utf8norm.h new file +111 -0
@@ -0,0 +1,111 @@ +/* +* Copyright (c) 2014 SGI. +* All rights reserved. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it would be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef UTF8NORM_H +#define UTF8NORM_H + +/* An opaque type used to determine the normalization in use. */ +typedef const struct utf8data *utf8data_t ; + +/* Encoding a unicode version number as a single unsigned int. */ +#define UNICODE_MAJ_SHIFT (16) +#define UNICODE_MIN_SHIFT (8) + +#define UNICODE_AGE (MAJ ,MIN ,REV ) \ + (((unsigned int)(MAJ) << UNICODE_MAJ_SHIFT) | \ + ((unsigned int)(MIN) << UNICODE_MIN_SHIFT) | \ + ((unsigned int)(REV))) + +/* Highest unicode version supported by the data tables. */ +extern const unsigned int utf8version; + +/* +* Look for the correct utf8data_t for a unicode version. +* Returns NULL if the version requested is too new. +* +* Two normalization forms are supported: nfkdi and nfkdicf. +* +* nfkdi: +* - Apply unicode normalization form NFKD. +* - Remove any Default_Ignorable_Code_Point. +* +* nfkdicf: +* - Apply unicode normalization form NFKD. +* - Remove any Default_Ignorable_Code_Point. +* - Apply a full casefold (C + F). +*/ +extern utf8data_t utf8nfkdi (unsigned int ); +extern utf8data_t utf8nfkdicf (unsigned int ); + +/* +* Determine the maximum age of any unicode character in the string. +* Returns 0 if only unassigned code points are present. +* Returns -1 if the input is not valid UTF-8. +*/ +extern int utf8agemax (utf8data_t ,const char *); +extern int utf8nagemax (utf8data_t ,const char *,size_t ); + +/* +* Determine the minimum age of any unicode character in the string. +* Returns 0 if any unassigned code points are present. +* Returns -1 if the input is not valid UTF-8. +*/ +extern int utf8agemin (utf8data_t ,const char *); +extern int utf8nagemin (utf8data_t ,const char *,size_t ); + +/* +* Determine the length of the normalized from of the string, +* excluding any terminating NULL byte. +* Returns 0 if only ignorable code points are present. +* Returns -1 if the input is not valid UTF-8. +*/ +extern ssize_t utf8len (utf8data_t ,const char *); +extern ssize_t utf8nlen (utf8data_t ,const char *,size_t ); + +/* +* Cursor structure used by the normalizer. +*/ +struct utf8cursor { +utf8data_t data; +const char *s; +const char *p; +const char *ss; +const char *sp; +unsigned int len; +unsigned int slen; +short int ccc; +short int nccc; +}; + +/* +* Initialize a utf8cursor to normalize a string. +* Returns 0 on success. +* Returns -1 on failure. +*/ +extern int utf8cursor (struct utf8cursor *,utf8data_t ,const char *); +extern int utf8ncursor (struct utf8cursor *,utf8data_t ,const char *,size_t ); + +/* +* Get the next byte in the normalization. +* Returns a value > 0 && < 256 on success. +* Returns 0 when the end of the normalization is reached. +* Returns -1 if the string being normalized is not valid UTF-8. +*/ +extern int utf8byte (struct utf8cursor *); + +#endif /* UTF8NORM_H */
libxfs/Makefile +1 -0
@@ -14,6 +14,7 @@ HFILES = xfs.h init.h xfs_dir2_priv.h crc32defs.h crc32table.h CFILES = cache.c \ crc32.c \ init.c kmem.c logitem.c radix-tree.c rdwr.c trans.c util.c \ + utf8norm.c \ xfs_alloc.c \ xfs_alloc_btree.c \ xfs_attr.c \
libxfs/utf8norm.c new file +628 -0
628 lines not on this page · raw message
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Hi,
Quoted 2 lines · Ben Myers
I'm posting this RFC for Unicode support in XFS on Olaf's behalf, as he is busy with other projects.
Patch 7 of each series is the trie generator and utf8 normalization module. Either it's just a little slow or it's over the message size limit on vger at a little over 100k. In case it's the latter I've placed them here:
ftp://oss.sgi.com/projects/xfs/tmp/18-Sep-14/0007-xfs-add-trie-generator-and-supporting-code-for-UTF-8.patch and ftp://oss.sgi.com/projects/xfs/tmp/18-Sep-14/0007-libxfs-add-trie-generator-and-supporting-code-for-UT.patch
I'll give it a while and then see about splitting up the patch.
Thanks,
Ben
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 9 lines · Ben Myers
Hi,
Quoted 2 lines · Ben Myers
I'm posting this RFC for Unicode support in XFS on Olaf's behalf, as he is busy with other projects.
Patch 7 of each series is the trie generator and utf8 normalization module. Either it's just a little slow or it's over the message size limit on vger at a little over 100k.
Probably, yeah:
http://vger.kernel.org/majordomo-info.html
"
* Message size exceeding 100 000 characters causes blocking.
"
- z
Quoted 9 lines · Zach Brown
Quoted 7 lines · Ben Myers
Quoted 2 lines · Ben Myers
I'm posting this RFC for Unicode support in XFS on Olaf's behalf, as he is busy with other projects.
Patch 7 of each series is the trie generator and utf8 normalization module. Either it's just a little slow or it's over the message size limit on vger at a little over 100k.
Quoted 7 lines
Probably, yeah:
http://vger.kernel.org/majordomo-info.html
"
* Message size exceeding 100 000 characters causes blocking.
"
D'oh! I'll split it up.
Thanks,
Ben
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 1/1 xfs: add trie generator for UTF-8.
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
mkutf8data.c is the source for a program that generates utf8data.h, which contains the trie that utf8norm.c uses. The trie is generated from the Unicode 7.0.0 data files. The format of the utf8data[] table is described in utf8norm.c, which is added in the next patch.
---
[v2: the trie is now separated into utf8norm.ko;
utf8version is now a function and exported;
introduced CONFIG_XFS_UTF8;
removed supporting code due to vger size constraint. --bpm]
---
fs/xfs/Kconfig | 8 +
fs/xfs/Makefile | 2 +-
fs/xfs/utf8norm/Makefile | 33 +
fs/xfs/utf8norm/mkutf8data.c | 3239 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 3281 insertions(+), 1 deletion(-)
create mode 100644 fs/xfs/utf8norm/Makefile
create mode 100644 fs/xfs/utf8norm/mkutf8data.cfs/xfs/Kconfig +8 -0
@@ -95,3 +95,11 @@ config XFS_DEBUG not useful unless you are debugging a particular problem. Say N unless you are an XFS developer, or you play one on TV. + +config XFS_UTF8 + bool "XFS UTF-8 support" + depends on XFS_FS + help + Say Y here to enable utf8 normalization support in XFS. You + will be able to mount and use filesystems created with the + utf8 mkfs.xfs option.
fs/xfs/Makefile +1 -1
@@ -21,7 +21,7 @@ ccflags-y += -I$(src)/libxfs ccflags-$(CONFIG_XFS_DEBUG) += -g -obj-$(CONFIG_XFS_FS) += xfs.o +obj-$(CONFIG_XFS_FS) += xfs.o utf8norm/ # this one should be compiled first, as the tracing macros can easily blow up xfs-y += xfs_trace.o
fs/xfs/utf8norm/Makefile new file +33 -0
@@ -0,0 +1,33 @@ +# +# Copyright (c) 2014 SGI. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +hostprogs-y := mkutf8data +$(obj)/utf8norm.o: $(obj)/utf8data.h +$(obj)/utf8data.h: $(src)/ucd/*.txt +$(obj)/utf8data.h: $(obj)/mkutf8data FORCE + $(call if_changed,mkutf8data) +quiet_cmd_mkutf8data = MKUTF8DATA $@ + cmd_mkutf8data = $(obj)/mkutf8data \ + -a $(src)/ucd/DerivedAge-7.0.0.txt \ + -c $(src)/ucd/DerivedCombiningClass-7.0.0.txt \ + -p $(src)/ucd/DerivedCoreProperties-7.0.0.txt \ + -d $(src)/ucd/UnicodeData-7.0.0.txt \ + -f $(src)/ucd/CaseFolding-7.0.0.txt \ + -n $(src)/ucd/NormalizationCorrections-7.0.0.txt \ + -t $(src)/ucd/NormalizationTest-7.0.0.txt \ + -o $@
fs/xfs/utf8norm/mkutf8data.c new file +3239 -0
2,948 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Part of the diff is not shown here. View the raw message.
PATCH 1/1 xfs: add supporting code for UTF-8.
In reply to Ben MyersFrom: Olaf Weber <[email protected]>
Supporting functions for UTF-8 normalization are in utf8norm.c with the header utf8norm.h. Two normalization forms are supported: nfkdi and nfkdicf.
nfkdi:
- Apply unicode normalization form NFKD.
- Remove any Default_Ignorable_Code_Point.
nfkdicf:
- Apply unicode normalization form NFKD.
- Remove any Default_Ignorable_Code_Point.
- Apply a full casefold (C + F).
For the purposes of the code, a string is valid UTF-8 if:
- The values encoded are 0x1..0x10FFFF.
- The surrogate codepoints 0xD800..0xDFFFF are not encoded.
- The shortest possible encoding is used for all values.
The supporting functions work on null-terminated strings (utf8 prefix) and on length-limited strings (utf8n prefix).
---
[v2: the trie is now separated into utf8norm.ko;
utf8version is now a function and exported;
introduced CONFIG_XFS_UTF8;
removed trie generator due to vger size constraint. --bpm]
---
fs/xfs/utf8norm/Makefile | 4 +
fs/xfs/utf8norm/utf8norm.c | 649 +++++++++++++++++++++++++++++++++++++++++++++
fs/xfs/utf8norm/utf8norm.h | 116 ++++++++
3 files changed, 769 insertions(+)
create mode 100644 fs/xfs/utf8norm/utf8norm.c
create mode 100644 fs/xfs/utf8norm/utf8norm.hfs/xfs/utf8norm/Makefile +4 -0
@@ -16,6 +16,10 @@ # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # +ifeq ($(CONFIG_XFS_UTF8),y) +obj-m += utf8norm.o +endif + hostprogs-y := mkutf8data $(obj)/utf8norm.o: $(obj)/utf8data.h $(obj)/utf8data.h: $(src)/ucd/*.txt
fs/xfs/utf8norm/utf8norm.c new file +649 -0
649 lines not on this page · raw message
fs/xfs/utf8norm/utf8norm.h new file +116 -0
116 lines not on this page · raw message
Signature · 6 lines
1.7.12.4 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Quoted 4 lines · Ben Myers
Strings are normalized using a trie that stores the relevant information. The trie itself is about 250kB in size, and lives in a separate module.
So 250kB bloat -- and what does this fix exactly?
Someone putting random ligatures into their file names and expecting the file to be the same as before. Can't they just not do that?
-Andi
Hey Andi,
Quoted 7 lines · Andi Kleen
Quoted 4 lines · Ben Myers
Strings are normalized using a trie that stores the relevant information. The trie itself is about 250kB in size, and lives in a separate module.
So 250kB bloat -- and what does this fix exactly?
We're trying to address the size issue by only loading the module when it's needed, but yeah it's big. Open to suggestions on how best to deal with that. I understand the sticker shock.
Quoted 2 lines
Someone putting random ligatures into their file names and expecting the file to be the same as before. Can't they just not do that?
The ligature example that Olaf gave might seem kind of trivial, but for other characters and languages could it be more significant?
As far as telling the customer "don't do that", my guess is that they would just go elsewhere. There are several other options for filesystems that support unicode.
Thanks,
Ben
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 3 lines
Quoted 1 line
So 250kB bloat -- and what does this fix exactly?
We're trying to address the size issue by only loading the module when
I'm not sure this is really addressing it.
Quoted 2 lines
it's needed, but yeah it's big. Open to suggestions on how best to deal with that. I understand the sticker shock.
I don't even understand why you need the whole table.
You want to not compare some special symbols, and a few other symbols are equivalent to others. But most symbols are only identical to themselves.
Couldn't you have a much smaller table that only expresses the exceptions?
Quoted 3 lines
As far as telling the customer "don't do that", my guess is that they would just go elsewhere. There are several other options for filesystems that support unicode.
They could put some code into their user app that generates an unique representation.
-Andi
Quoted 5 lines · Andi Kleen
Quoted 3 lines
Quoted 1 line
So 250kB bloat -- and what does this fix exactly?
We're trying to address the size issue by only loading the module when
I'm not sure this is really addressing it.
You only pay the space cost if you use it, similar to the nls tables.
Quoted 10 lines
Quoted 2 lines
it's needed, but yeah it's big. Open to suggestions on how best to deal with that. I understand the sticker shock.
I don't even understand why you need the whole table.
You want to not compare some special symbols, and a few other symbols are equivalent to others. But most symbols are only identical to themselves.
Couldn't you have a much smaller table that only expresses the exceptions?
The trie tells you whether a given sequence of bytes is a UTF-8 encoded unicode codepoint, and if so, it gives the unicode version in which the codepoint was assigned an interpretation (if any), the canonical combining class (required for normalization), and the decomposition and case fold (if any).
A big part of the table does decompositions for Korean: eliminating the Hangul decompositions removes 156320 bytes, leaving 89936 bytes.
Hangul decomposition uses two or three unicode code points and a terminating NUL byte in a UTF-8 string. The code points each require a three-byte UTF-8 sequence, so the total is 7 bytes per 2-part decomposition, and 10 bytes per 3-part decomposition.
With that in mind, the 156320 additional bytes spent on Hangul are accounted for as follows:
22344 bytes : 11172 leaves * 2 byte leaf size
2793 bytes : 399 2-part decompositions at 7 bytes each
107730 bytes : 10773 3-part decompositions at 10 bytes each
This adds up to 132867 bytes of data, with the remainder, 23453 bytes, spent on additional internal trie nodes.
Quoted 6 lines
Quoted 3 lines
As far as telling the customer "don't do that", my guess is that they would just go elsewhere. There are several other options for filesystems that support unicode.
They could put some code into their user app that generates an unique representation.
This assumes a single app, and that they control the source of that app.
Olaf
Signature · 9 lines
Olaf Weber SGI Phone: +31(0)30-6696796
Veldzigt 2b Fax: +31(0)30-6696799
Technical Lead 3454 PW de Meern Vnet: 955-6796
Storage Software The Netherlands Email: [email protected]
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfsQuoted 1 line
You only pay the space cost if you use it, similar to the nls tables.
The way Linux module loading works these things are loaded by default, not when someone needs it.
So no, you (or rather every unfortunate Linux XFS user) would pay it always, unless you black list the module or rebuild the kernel.
Quoted 2 lines
A big part of the table does decompositions for Korean: eliminating the Hangul decompositions removes 156320 bytes, leaving 89936 bytes.
Are there regular ranges or other redundancies in the Korean encoding that could be used to compress paths?
Doing some basic research other people already answered this:
Please use the ICU or google tables referenced below. Apparently smaller is possible too, but 40-50k seems more reasonable.
I'm just gonna make the claim that whatever performance you get from a larger table is dwarfed by the cache miss overhead.
----
http://macchiato.com/unicode/normalization_footprint.htm
http://www.macchiato.com/unicode/nfc-faq
NFC normalization requires large tables, right?
Like many other cases, there is a tradeoff between size and performance. You can use very small tables, at some cost in performance. (Even there, the actual performance cost depends on how often normalization needs to be invoked, as discussed above.)
To see an analysis of the situation, see Normalization Footprint. It is a bit out of date, but gives a sense of the magnitude. For comparison, ICU's optimized tables for NFC take 44 kB (UTF-16) and Google's optimized tables for NFC take 46 kB (UTF-8).
-Andi
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Hi Andi,
Quoted 7 lines · Andi Kleen
Quoted 1 line
You only pay the space cost if you use it, similar to the nls tables.
The way Linux module loading works these things are loaded by default, not when someone needs it.
So no, you (or rather every unfortunate Linux XFS user) would pay it always, unless you black list the module or rebuild the kernel.
The suggestion to use symbol_get was made in response to the initial post of the series. In my testing the normalization module did not load until I attempted to mount a filesystem which required it. Seems to work ok.
See patch 10, "xfs: implement demand load of utf8norm.ko".
Thanks,
Ben
Quoted 5 lines · Andi Kleen
Quoted 2 lines
A big part of the table does decompositions for Korean: eliminating the Hangul decompositions removes 156320 bytes, leaving 89936 bytes.
Are there regular ranges or other redundancies in the Korean encoding that could be used to compress paths?
Yes, though at the expense of more complicated code and interfaces. in particular, lookups that want a normalized string would need to provide a 10-byte buffer to store it in.
Quoted 4 lines
Doing some basic research other people already answered this:
Please use the ICU or google tables referenced below. Apparently smaller is possible too, but 40-50k seems more reasonable.
Riffing off the http://macchiato.com/unicode/normalization_footprint.htm link you provided, looking at the NFKD case. For Unicode 3.0.0 that link gives 3483 NFKD normalizations (exlcuding Hangul), and gives 26,918 bytes as the size of a simple lookup table (key/offset pairs, with the offset pointing into a string table).
In Unicode 7.0.0 I count 5721 NFKD normalizations (again excluding Hangul).
As NUL-terminated UTF-8 strings these take 23390 bytes. Using a
key-offset table I need 3 bytes for the key (code points are 21 bits) and 2 bytes for an offset. Total is 5721 * (3 + 2) + 23390 = 51995 bytes. Stealing 4 bits from the key field and 1 from the offset to store the size of the normalized string I can remove the NUL bytes from the string table and reduce total size to 46274 bytes.
The trie implementation used here would use 66283 bytes to store the same information, but it also provides unicode version and canonical combining class for all codepoints. There are 10268 leaves in this case, with the size of each leaf being 1 byte for version, one for ccc, plus the size of the decomposition, if any. So a quick estimate on the space used just for the NFKD data is some 45747 bytes.
I'm pretty certain that a trie that only stores the NFKD would be smaller than 45747 bytes as it would need fewer internal nodes, but didn't do the experiment. But as you can see, for just the NFKD part and excluding Hangul, the size of the trie is within the ballpark of the numbers you gave.
Case folding adds a partial trie that forwards to the "main" trie for parts that are identical. This adds 2672 extra leaves and 20171 extra bytes. The data for the normalization corrections adds another 3328 bytes. With a bit of rounding, total size comes to 89840 bytes.
Quoted 2 lines
I'm just gonna make the claim that whatever performance you get from a larger table is dwarfed by the cache miss overhead.
That's possible, though it seems plausible you'd only suffer from this doing actual Hangul decomposition: all the data related to this (trie nodes, trie leaves, and strings) sits in one contiguous block in memory.
Olaf
Signature · 9 lines
Olaf Weber SGI Phone: +31(0)30-6696796
Veldzigt 2b Fax: +31(0)30-6696799
Technical Lead 3454 PW de Meern Vnet: 955-6796
Storage Software The Netherlands Email: [email protected]
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfsQuoted 11 lines · Olaf Weber
Quoted 5 lines · Andi Kleen
Quoted 2 lines
A big part of the table does decompositions for Korean: eliminating the Hangul decompositions removes 156320 bytes, leaving 89936 bytes.
Are there regular ranges or other redundancies in the Korean encoding that could be used to compress paths?
Yes, though at the expense of more complicated code and interfaces. in particular, lookups that want a normalized string would need to provide a 10-byte buffer to store it in.
I spent some time working on this, and the effect on the lookup code isn't as bad as I'd thought. The updated code should be posted early next week.
With this change, the table size for the full trie becomes 89952 bytes. Of this, 66400 bytes are spent on the NFKD + Ignorables, an additional 20992 bytes on NFDK + Ignorables + Case Fold. The remainder, 2560 bytes, are additional info for older unicode versions.
Note that the NFDK + Ignorables + Case Fold trie forwards to the NFKD + Ignorables where they overlap. A stand-alone version would be 71750 bytes.
As noted before these tables also contain the Canonical Combining Class and unicode version information for the code points. The latter allows for supporting multiple unicode versions using a single combined table.
Olaf
Signature · 9 lines
Olaf Weber SGI Phone: +31(0)30-6696796
Veldzigt 2b Fax: +31(0)30-6696799
Technical Lead 3454 PW de Meern Vnet: 955-6796
Storage Software The Netherlands Email: [email protected]
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfsQuoted 10 lines · Andi Kleen
Quoted 4 lines · Ben Myers
Strings are normalized using a trie that stores the relevant information. The trie itself is about 250kB in size, and lives in a separate module.
So 250kB bloat -- and what does this fix exactly?
Someone putting random ligatures into their file names and expecting the file to be the same as before. Can't they just not do that?
I like the 'office' example because it is applicable to English and easy to explain. Once you move away from English examples are much easier to come by. Take a Dutch name like 'Renée Soutendijk'.
These two forms both spell Renée in UTF-8:
0x52 0x65 0x6E 0xC3 0xA9 0x65
0x52 0x65 0x6E 0x65 0xCC 0x81 0x65
The difference is
LATIN SMALL LETTER E WITH ACUTE (U+00E9)
LATIN SMALL LETTER E (U+0065) COMBINING ACUTE ACCENT (U+0301)
and corresponds to the difference between NFC and NFD.
These two forms both spell Soutendijk in UTF-8:
0x53 0x6F 0x75 0x74 0x65 0x6E 0x64 0x69 0x6A 0x6B
0x53 0x6F 0x75 0x74 0x65 0x6E 0x64 0xC4 0xB3 0x6B
The difference is
LATIN SMALL LETTER I (U+0069) LATIN SMALL LETTER J (U+006A)
LATIN SMALL LIGATURE IJ (U+0133)
and the former is the compatibility decomposition of the latter, the 'K' in NFKC/NFKD.
Do accented letters count as random ligatures that people should just not use?
The bulk of the table deals with Korean.
Olaf
Signature · 9 lines
Olaf Weber SGI Phone: +31(0)30-6696796
Veldzigt 2b Fax: +31(0)30-6696799
Technical Lead 3454 PW de Meern Vnet: 955-6796
Storage Software The Netherlands Email: [email protected]
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfsQuoted 2 lines
The bulk of the table deals with Korean.
Is a table of Korean exceptions 250k too?
If not please find some other way to compress this.
I'm sure there is redundancy somewhere.
-Andi
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 19 lines · Ben Myers
Hi,
I'm posting this RFC for Unicode support in XFS on Olaf's behalf, as he is busy with other projects. This is the second revision of the series. The first is available here:
http://oss.sgi.com/archives/xfs/2014-09/msg00169.html
In response to the initial feedback, the changes in version 2 include:
* linux-fsdevel in the To: line,
* Updated design notes,
* Separation of the fs-independent trie and support code into utf8norm.ko,
* A mechanism for loading the normalization module only when necessary.I'll post the whole series for completeness sake. Many on -fsdevel will not be interested in the xfs-specific bits, but it may be helpful to have the full series as an example and for testing purposes.
Quoted 7 lines
First there is a set of kernel bits, then some libxfs/xfsprogs stuff, and finally a test. (Note: I am not posting the unicode database files due to their large size. There are scripts to download them from unicode.org in the relevant commit headers.)
TODO: Store the unicode version number of the filesystem on disk in the super block.
So, if the filesystem has to store the specific unicode version it was created with so that we know what version to put in trie lookups, again I'll ask: why are we loading the trie as a generic kernel module and not as metadata in the filesystem that is demand paged and cached?
i.e. put the entire trie on disk, look up the specific conversion required for the name being compared, and then cache that conversion in memory. This makes repeated lookups much faster because the trie only contains conversions that are in use, the memory footprint is way lower and the conversions are guaranteed to be consistent for the life of the filesystem....
Quoted 19 lines
Here are Olaf's design notes:
-----------------------------------------------------------------------------
Unicode/UTF-8 support for XFSSo we had a customer request proper unicode support...
* What does "supporting unicode" actually mean?
From a text processing point of view, what a filesystem does with filenames is simple: it stores and retrieves them, and compares them for equality. It may reject certain byte sequences as invalid filenames (for example, no filename can contain an ASCII NUL).
I've been taking it as a given that when a file is created with a certain byte sequence as its name, then a subsequent directory listing will contain that same byte sequence among the names listed.
Quoted 6 lines
This leaves comparing names for equality, and in my view this is what "supporting unicode" revolves about.
The present state of affairs is that different byte sequences are different filenames. This amounts to tolerating unicode without actually supporting it.
That's somewhat circular - using your own definition of "supported" to argue that your own definition is the right one....
Quoted 11 lines
To support unicode we have to interpret filenames. What happens when (part of) a filename cannot be interpreted? We can reject the filename, interpret the parts we can, or punt and accept it as an uninterpreted blob.
Rejecting ill-formed filenames was my first choice, but I came around on the issue: there are too many ways in which you can end up with having to deal with ill-formed filenames that would leave a user with no recourse but to move whatever they're doing to a different filesystem. Unpacking a tarball with filenames in a different encoding is an example.
You still haven't addressed this:
| So we accept invalid unicode in filenames, but only after failing to | parse them? Isn't this a potential vector for exploiting weaknesses | in application filename handling? i.e. unprivileged user writes | specially crafted invalid unicode filename to disk, setuid program | tries to parse it, invalid sequence triggers a buffer overflow bug | in setuid parser?
apart from handwaving that userspace has to be able to handle invalid utf-8 already. Why should we let filesystems say "we fully understand and support utf8" and then allow them to accept and propagate invalid utf8 sequences and leave everyone else to have to clean up the mess?
Quoted 7 lines
Partial interpretation of an ill-formed filename just strikes me as the kind of bad idea that most half-houses are. I admit that I have no stronger objection to this than the fact that it makes the code even more complicated and fragile.
Which leaves "blob" as the preferred option by default for coping with ill-formed filenames.
And so can't be case-folded, leading to inconsistent behaviour of case-insensitive filename comparisons.
I don't blindly subscribe to the robustness principle of "be liberal with what you accept". Being liberal means accepting malformed junk and then trying to make good. It's a fool's game - we've learnt time and time again that if we don't fully validate string inputs that we have to interpret then someone will find an exploit that utilises malformed strings. I don't think we should expose core kernel code to such structural weaknesses...
Quoted 8 lines
When comparing well-formed filenames, the question now becomes which byte sequences are considered to be alternative spellings of the same filename. This is where normalization forms come into play, and the unicode standard has quite a bit to say about the subject.
If all you're doing is comparison, then choosing NFD over NFC is easy, because the former is easier to calculate than the latter.
Quoted 7 lines
If you want various spellings of "office" to compare equal, then picking NFKD over NFD for comparison is also an obvious choice. (Hand-picking individual compatibility forms is truly a bad idea.) Ways to spell "office": "
o_f_f_i_c_e", "o_f_fi_c_e", and "o_ffi_c_e", using no ligatures, the fi ligature, or the ffi ligature. (Some fool thought it a good idea to add these ligatures to unicode, all we get to decide is how to cope.)
Yet normalised strings are only stable and hence comparable if there are no unassigned code points in them. What happens when userspace is not using the same version of unicode as the filesystem and is using newer code points in it's strings? Normalisation fails, right?
And as an extension of using normalisation for case-folded comparisons, how do we make case folding work with blobs that can't be normalised? It seems to me that this just leads to the nasty situation where some filenames are case sensitive and some aren't based on what the filesystem thinks is valid utf-8. The worst part is that userspace has no idea that the filesystem is making such distinctions and so behaviour is not at all predictable or expected.
This is another point in favour of rejecting invalid utf-8 strings and for keeping the translation tables stable within the filesystem...
Quoted 8 lines
The most contentious part is (should be) ignoring the codepoints with the
Default_Ignorable_Code_Pointproperty. I've included the list below. My argument, such as it is, is that these code points either have no visible rendering, or in cases like the soft hyphen, are only conditionally visible. The problem with these (as I see it) is that on seeing a filename that might contain them you cannot tell whether they are present. So I propose to ignore them for the purpose of comparing filenames for equality.
Which introduces a non-standard "visibility criterial" for determining what should be or shouldn't be part of the normalised string for comparison. I don't see any real justification for stepping outside the standard unicode normalisation here - just because the user cannot see a character in a specific context does not mean that it is not significant to the application that created it.
Quoted 8 lines
Finally, case folding. First of all, it is optional. Then the issue is that you either go the language-specific route, or simplify the task by "just" doing a full casefold (C+F, in unicode parlance). Looking around the net I tend to find that if you're going to do casefolding at all, then a language-independent full casefold is preferred because it is the most predictable option. See
http://www.w3.org/TR/charmod-norm/ for an example of that kind of reasoning.
Which says in section 2.4: "Some languages need case-folding to be tailored to meet specific linguistic needs". That implies that the case folding needs to be language aware and hence needs to be tied into the NLS subsystem for handling specific quirks like Turkic.
I also note that it says in several places that C+F can result in a folded string of a different length. What happens when that folded string is longer than 255 bytes and hence longer than NAME_MAX? That's a bit of a nasty landmine for pathname string handling functions - developers are going to assume that pathname components are not longer than NAME_MAX, and if we are passing normalised strings around that is not a valid assumption....
Quoted 1 line
* XFS-specific design notes.
...
Quoted 4 lines
If the borgbit (the bit enabling legacy ASCII-based CI in XFS) is set in the superblock, then case folding is added into the mix. This is the nfkdicf normalization form mentioned above. It allows for the creation of case-insensitive filesystems with UTF-8 support.
Please don't overload existing superblock feature bits with multiple meanings. ASCII-CI is a stand-alone feature and is not in any way compatible with Unicode: Unicode-CI is a superset of Unicode support. So it really needs two new feature bits for Unicode and Unicode-CI, not just one for unicode.
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Quoted 1 line · Dave Chinner
On Thu, Sep 18, 2014 at 02:56:50PM -0500, Ben Myers wrote:
[...]
Quoted 8 lines
Quoted 2 lines
TODO: Store the unicode version number of the filesystem on disk in the super block.
So, if the filesystem has to store the specific unicode version it was created with so that we know what version to put in trie lookups, again I'll ask: why are we loading the trie as a generic kernel module and not as metadata in the filesystem that is demand paged and cached?
This way the trie can be shared, and the code using it is not entangled with the XFS code.
Quoted 6 lines
i.e. put the entire trie on disk, look up the specific conversion required for the name being compared, and then cache that conversion in memory. This makes repeated lookups much faster because the trie only contains conversions that are in use, the memory footprint is way lower and the conversions are guaranteed to be consistent for the life of the filesystem....
Above you mention demand paging parts of the trie, but here you seem to suggest creating an in-core conversion table on the fly from data read from disk. The former seems a lot easier to do than the latter.
Quoted 50 lines
Quoted 19 lines
Here are Olaf's design notes:
-----------------------------------------------------------------------------
Unicode/UTF-8 support for XFSSo we had a customer request proper unicode support...
* What does "supporting unicode" actually mean?
From a text processing point of view, what a filesystem does with
filenames is simple: it stores and retrieves them, and compares them for equality. It may reject certain byte sequences as invalid filenames (for example, no filename can contain an ASCII NUL).I've been taking it as a given that when a file is created with a certain byte sequence as its name, then a subsequent directory listing will contain that same byte sequence among the names listed.
Quoted 6 lines
This leaves comparing names for equality, and in my view this is what "supporting unicode" revolves about.
The present state of affairs is that different byte sequences are different filenames. This amounts to tolerating unicode without actually supporting it.
That's somewhat circular - using your own definition of "supported" to argue that your own definition is the right one....
Quoted 11 lines
To support unicode we have to interpret filenames. What happens when (part of) a filename cannot be interpreted? We can reject the filename, interpret the parts we can, or punt and accept it as an uninterpreted blob.
Rejecting ill-formed filenames was my first choice, but I came around on the issue: there are too many ways in which you can end up with having to deal with ill-formed filenames that would leave a user with no recourse but to move whatever they're doing to a different filesystem. Unpacking a tarball with filenames in a different encoding is an example.
You still haven't addressed this:
| So we accept invalid unicode in filenames, but only after failing to | parse them? Isn't this a potential vector for exploiting weaknesses | in application filename handling? i.e. unprivileged user writes | specially crafted invalid unicode filename to disk, setuid program | tries to parse it, invalid sequence triggers a buffer overflow bug | in setuid parser?
Quoted 5 lines
apart from handwaving that userspace has to be able to handle invalid utf-8 already. Why should we let filesystems say "we fully understand and support utf8" and then allow them to accept and propagate invalid utf8 sequences and leave everyone else to have to clean up the mess?
Because the alternative amounts in my opinion to a demand that every bit of userspace that may be involved in generating filenames generate only clean UTF-8. I do not believe that this is a realistic demand at this point in time.
Quoted 11 lines
Quoted 7 lines
Partial interpretation of an ill-formed filename just strikes me as the kind of bad idea that most half-houses are. I admit that I have no stronger objection to this than the fact that it makes the code even more complicated and fragile.
Which leaves "blob" as the preferred option by default for coping with ill-formed filenames.
And so can't be case-folded, leading to inconsistent behaviour of case-insensitive filename comparisons.
Quoted 7 lines
I don't blindly subscribe to the robustness principle of "be liberal with what you accept". Being liberal means accepting malformed junk and then trying to make good. It's a fool's game - we've learnt time and time again that if we don't fully validate string inputs that we have to interpret then someone will find an exploit that utilises malformed strings. I don't think we should expose core kernel code to such structural weaknesses...
This is why I prefer not to interpret strings that are not UTF-8. I just don't think we can afford to outright reject them.
Quoted 16 lines
Quoted 8 lines
When comparing well-formed filenames, the question now becomes which byte sequences are considered to be alternative spellings of the same filename. This is where normalization forms come into play, and the unicode standard has quite a bit to say about the subject.
If all you're doing is comparison, then choosing NFD over NFC is easy, because the former is easier to calculate than the latter.
Quoted 7 lines
If you want various spellings of "office" to compare equal, then picking NFKD over NFD for comparison is also an obvious choice. (Hand-picking individual compatibility forms is truly a bad idea.) Ways to spell "office": "
o_f_f_i_c_e", "o_f_fi_c_e", and "o_ffi_c_e", using no ligatures, the fi ligature, or the ffi ligature. (Some fool thought it a good idea to add these ligatures to unicode, all we get to decide is how to cope.)
Quoted 5 lines
Yet normalised strings are only stable and hence comparable if there are no unassigned code points in them. What happens when userspace is not using the same version of unicode as the filesystem and is using newer code points in it's strings? Normalisation fails, right?
For the newer code points, yes. This is not treated as a failure to normalize the string as a whole, as there are clear guidelines in unicode on how unassigned code points interact with normalization: they have canonical combining class 0 and no decomposition.
Quoted 7 lines
And as an extension of using normalisation for case-folded comparisons, how do we make case folding work with blobs that can't be normalised? It seems to me that this just leads to the nasty situation where some filenames are case sensitive and some aren't based on what the filesystem thinks is valid utf-8. The worst part is that userspace has no idea that the filesystem is making such distinctions and so behaviour is not at all predictable or expected.
Making case-folding work on a blob that cannot be normalized is (in my opinion) akin to doing an ASCII-based casefold on a Shift-JIS string: the result is neither pretty nor useful.
Quoted 3 lines
This is another point in favour of rejecting invalid utf-8 strings and for keeping the translation tables stable within the filesystem...
Bear in mind that this means not just rejecting invalid UTF-8 strings, but also rejecting valid UTF-8 strings that encode unassigned code points.
This should be easy to implement if it is decided that we want to do this.
Quoted 9 lines
Quoted 8 lines
The most contentious part is (should be) ignoring the codepoints with the
Default_Ignorable_Code_Pointproperty. I've included the list below. My argument, such as it is, is that these code points either have no visible rendering, or in cases like the soft hyphen, are only conditionally visible. The problem with these (as I see it) is that on seeing a filename that might contain them you cannot tell whether they are present. So I propose to ignore them for the purpose of comparing filenames for equality.
Quoted 7 lines
Which introduces a non-standard "visibility criterial" for determining what should be or shouldn't be part of the normalised string for comparison. I don't see any real justification for stepping outside the standard unicode normalisation here - just because the user cannot see a character in a specific context does not mean that it is not significant to the application that created it.
I agree these characters may be significant to the application. I'm just not convinced that they should be significant in a file name.
Quoted 9 lines
Quoted 8 lines
Finally, case folding. First of all, it is optional. Then the issue is that you either go the language-specific route, or simplify the task by "just" doing a full casefold (C+F, in unicode parlance). Looking around the net I tend to find that if you're going to do casefolding at all, then a language-independent full casefold is preferred because it is the most predictable option. See
http://www.w3.org/TR/charmod-norm/ for an example of that kind of reasoning.
Quoted 4 lines
Which says in section 2.4: "Some languages need case-folding to be tailored to meet specific linguistic needs". That implies that the case folding needs to be language aware and hence needs to be tied into the NLS subsystem for handling specific quirks like Turkic.
It also recommends just doing a full case fold for cases where you are ignorant of the language actually in use. In section 3.1 they say: "However, language-sensitive case-sensitive matching in document formats and protocols is NOT RECOMMENDED because language information can be hard to obtain, verify, or manage and the resulting operations can produce results that frustrate users." This doesn't exactly address the case of filesystems, but as far as I know there is no defined interface that allows kernel code to query the locale settings that currently apply to a userspace process.
Quoted 7 lines
I also note that it says in several places that C+F can result in a folded string of a different length. What happens when that folded string is longer than 255 bytes and hence longer than
NAME_MAX? That's a bit of a nasty landmine for pathname string handling functions - developers are going to assume that pathname components are not longer thanNAME_MAX, and if we are passing normalised strings around that is not a valid assumption....
This is not just true for case folding: normalization may also change string length, and NFD or NFKD will typically increase the length.
That is among the reasons why normalized and case folded strings are not stored on disk, and are not passed up to other parts of the kernel. The code posted will generate a normalized version of the user-provided string used to look up data as a way to cache that normalization and to reduce stack pressure a bit, but this string is ephemeral and discarded once lookup is complete.
Quoted 7 lines
Quoted 1 line
* XFS-specific design notes.
...
Quoted 4 lines
If the borgbit (the bit enabling legacy ASCII-based CI in XFS) is set in the superblock, then case folding is added into the mix. This is the nfkdicf normalization form mentioned above. It allows for the creation of case-insensitive filesystems with UTF-8 support.
Quoted 5 lines
Please don't overload existing superblock feature bits with multiple meanings. ASCII-CI is a stand-alone feature and is not in any way compatible with Unicode: Unicode-CI is a superset of Unicode support. So it really needs two new feature bits for Unicode and Unicode-CI, not just one for unicode.
It seemed an obvious extension of the meaning of that bit.
Olaf
Signature · 9 lines
Olaf Weber SGI Phone: +31(0)30-6696796
Veldzigt 2b Fax: +31(0)30-6696799
Technical Lead 3454 PW de Meern Vnet: 955-6796
Storage Software The Netherlands Email: [email protected]
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfsQuoted 8 lines · Olaf Weber
Quoted 1 line · Dave Chinner
On Thu, Sep 18, 2014 at 02:56:50PM -0500, Ben Myers wrote:
[...]
Quoted 3 lines
Quoted 2 lines
TODO: Store the unicode version number of the filesystem on disk in the super block.
Quoted 8 lines
Quoted 5 lines
So, if the filesystem has to store the specific unicode version it was created with so that we know what version to put in trie lookups, again I'll ask: why are we loading the trie as a generic kernel module and not as metadata in the filesystem that is demand paged and cached?
This way the trie can be shared, and the code using it is not entangled with the XFS code.
The trie parsing code can still be common - just the location and contents of the data is determined by the end-user.
Quoted 11 lines
Quoted 7 lines
i.e. put the entire trie on disk, look up the specific conversion required for the name being compared, and then cache that conversion in memory. This makes repeated lookups much faster because the trie only contains conversions that are in use, the memory footprint is way lower and the conversions are guaranteed to be consistent for the life of the filesystem....
Above you mention demand paging parts of the trie, but here you seem to suggest creating an in-core conversion table on the fly from data read from disk. The former seems a lot easier to do than the latter.
Right - it's a question of what needs optimising. If people are only concerned about memory footprint, then demand paging solves that problem. If people are concerned about performance and memory footprint, then demand paging plus a lookaside cache
will address both of those aspects.
We can't do demand paging if the trie data is built into the kernel. We can still do a lookaside cache to avoid performane issues with repeated trie lookups...
[...]
Quoted 27 lines
Quoted 21 lines
Quoted 11 lines
To support unicode we have to interpret filenames. What happens when (part of) a filename cannot be interpreted? We can reject the filename, interpret the parts we can, or punt and accept it as an uninterpreted blob.
Rejecting ill-formed filenames was my first choice, but I came around on the issue: there are too many ways in which you can end up with having to deal with ill-formed filenames that would leave a user with no recourse but to move whatever they're doing to a different filesystem. Unpacking a tarball with filenames in a different encoding is an example.
You still haven't addressed this:
| So we accept invalid unicode in filenames, but only after failing to | parse them? Isn't this a potential vector for exploiting weaknesses | in application filename handling? i.e. unprivileged user writes | specially crafted invalid unicode filename to disk, setuid program | tries to parse it, invalid sequence triggers a buffer overflow bug | in setuid parser?Quoted 5 lines
apart from handwaving that userspace has to be able to handle invalid utf-8 already. Why should we let filesystems say "we fully understand and support utf8" and then allow them to accept and propagate invalid utf8 sequences and leave everyone else to have to clean up the mess?
Quoted 4 lines
Because the alternative amounts in my opinion to a demand that every bit of userspace that may be involved in generating filenames generate only clean UTF-8. I do not believe that this is a realistic demand at this point in time.
It's a chicken and egg situation. I'd much prefer we enforce clean utf8 from the start, because if we don't we'll never be able to do that. And other filesystems (e.g. ZFS) allow you to do reject anything that is not clean utf8....
[...]
Quoted 22 lines
Quoted 16 lines
Quoted 8 lines
When comparing well-formed filenames, the question now becomes which byte sequences are considered to be alternative spellings of the same filename. This is where normalization forms come into play, and the unicode standard has quite a bit to say about the subject.
If all you're doing is comparison, then choosing NFD over NFC is easy, because the former is easier to calculate than the latter.
Quoted 7 lines
If you want various spellings of "office" to compare equal, then picking NFKD over NFD for comparison is also an obvious choice. (Hand-picking individual compatibility forms is truly a bad idea.) Ways to spell "office": "
o_f_f_i_c_e", "o_f_fi_c_e", and "o_ffi_c_e", using no ligatures, the fi ligature, or the ffi ligature. (Some fool thought it a good idea to add these ligatures to unicode, all we get to decide is how to cope.)Quoted 5 lines
Yet normalised strings are only stable and hence comparable if there are no unassigned code points in them. What happens when userspace is not using the same version of unicode as the filesystem and is using newer code points in it's strings? Normalisation fails, right?
Quoted 4 lines
For the newer code points, yes. This is not treated as a failure to normalize the string as a whole, as there are clear guidelines in unicode on how unassigned code points interact with normalization:
they have canonical combining class 0 and no decomposition.
And so effectively are not stable. Which is something we absolutely have to avoid for information stored on disk. i.e. you're using the normalised form to build the hash values in the lookup index in the directory structure, and so having unstable normalisation forms is just wrong. Hence we'd need to reject anything with unassigned code points....
Quoted 11 lines
Quoted 7 lines
And as an extension of using normalisation for case-folded comparisons, how do we make case folding work with blobs that can't be normalised? It seems to me that this just leads to the nasty situation where some filenames are case sensitive and some aren't based on what the filesystem thinks is valid utf-8. The worst part is that userspace has no idea that the filesystem is making such distinctions and so behaviour is not at all predictable or expected.
Making case-folding work on a blob that cannot be normalized is (in my opinion) akin to doing an ASCII-based casefold on a Shift-JIS
string: the result is neither pretty nor useful.
Yes, that's exactly my point.
Quoted 7 lines
Quoted 3 lines
This is another point in favour of rejecting invalid utf-8 strings and for keeping the translation tables stable within the filesystem...
Bear in mind that this means not just rejecting invalid UTF-8 strings, but also rejecting valid UTF-8 strings that encode unassigned code points.
And that's precisely what I'm suggesting: If we can't normalise the filename to a stable form then it cannot be used for hashing or case folding. That means it needs to be rejected, not treated as an opaque blob.
The moment we start parsing filenames they are no longer opaque blobs and so all existing "filename are opaque blobs" handling rules go out the window. They are now either valid so we can use them, or they are invalid and need to be rejected to avoid unpredictable and/or undesirable behaviour.
Quoted 19 lines
This should be easy to implement if it is decided that we want to do this.
Quoted 9 lines
Quoted 8 lines
The most contentious part is (should be) ignoring the codepoints with the
Default_Ignorable_Code_Pointproperty. I've included the list below. My argument, such as it is, is that these code points either have no visible rendering, or in cases like the soft hyphen, are only conditionally visible. The problem with these (as I see it) is that on seeing a filename that might contain them you cannot tell whether they are present. So I propose to ignore them for the purpose of comparing filenames for equality.Quoted 7 lines
Which introduces a non-standard "visibility criterial" for determining what should be or shouldn't be part of the normalised string for comparison. I don't see any real justification for stepping outside the standard unicode normalisation here - just because the user cannot see a character in a specific context does not mean that it is not significant to the application that created it.
Quoted 2 lines
I agree these characters may be significant to the application. I'm just not convinced that they should be significant in a file name.
They are significant to the case folding result, right? And therefore would be significant in a filename...
Quoted 15 lines
Quoted 10 lines
Quoted 9 lines
Finally, case folding. First of all, it is optional. Then the issue is that you either go the language-specific route, or simplify the task by "just" doing a full casefold (C+F, in unicode parlance). Looking around the net I tend to find that if you're going to do casefolding at all, then a language-independent full casefold is preferred because it is the most predictable option. See
http://www.w3.org/TR/charmod-norm/ for an example of that kind of reasoning.Quoted 4 lines
Which says in section 2.4: "Some languages need case-folding to be tailored to meet specific linguistic needs". That implies that the case folding needs to be language aware and hence needs to be tied into the NLS subsystem for handling specific quirks like Turkic.
Quoted 9 lines
It also recommends just doing a full case fold for cases where you are ignorant of the language actually in use. In section 3.1 they
say: "However, language-sensitive case-sensitive matching in document formats and protocols is NOT RECOMMENDED because language information can be hard to obtain, verify, or manage and the resulting operations can produce results that frustrate users." This doesn't exactly address the case of filesystems, but as far as I know there is no defined interface that allows kernel code to query the locale settings that currently apply to a userspace process.
Hence my comments about NLS integration. The NLS subsystem already has utf8 support with language dependent case folding tables. All the current filesystems that deal with unicode (including case folding) use the NLS subsystem for conversions.
Hmmm - looking at all the NLS code that does different utf format conversions first: what happens if an application is using UTF16 or UTF32 for it's filename encoding rather than utf8?
Quoted 7 lines
Quoted 7 lines
Quoted 1 line
* XFS-specific design notes.
...
Quoted 4 lines
If the borgbit (the bit enabling legacy ASCII-based CI in XFS) is set in the superblock, then case folding is added into the mix. This is the nfkdicf normalization form mentioned above. It allows for the creation of case-insensitive filesystems with UTF-8 support.
Quoted 7 lines
Quoted 5 lines
Please don't overload existing superblock feature bits with multiple meanings. ASCII-CI is a stand-alone feature and is not in any way compatible with Unicode: Unicode-CI is a superset of Unicode support. So it really needs two new feature bits for Unicode and Unicode-CI, not just one for unicode.
It seemed an obvious extension of the meaning of that bit.
Feature bits refer to a specific on disk format feature. If that bit is set, then that feature is present. In this case, it means the filesystem is using ascii-ci. If that bit is passed out to userspace via the geometry ioctl, then *existing applications* expect it to mean ascii-ci behaviour from the filesystem. If an existing utility reads the flag field from disk (e.g. repair, metadump, db, etc) they all expect it to mean ascii-ci, and will do stuff based on that specific meaning. We cannot redefine the meaning of a feature bit after the fact - we have lots of feature bits so there's no need to overload an existing one for this.
Hmmm - another interesting question just popped into my head about
metadump: file name obfuscation. What does unicode and utf8 mean for the hash collision calculation algorithm?
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Quoted 25 lines
-----Original Message-----
From: [email protected] [mailto:linux-fsdevel- [email protected]] On Behalf Of Dave Chinner
Sent: Wednesday, September 24, 2014 7:10 PM
To: Olaf Weber
Cc: Ben Myers; [email protected]; [email protected]; [email protected]
Subject: Re: [RFC v2] Unicode/UTF-8 support for XFSQuoted 14 lines · Olaf Weber
Quoted 1 line · Dave Chinner
On Thu, Sep 18, 2014 at 02:56:50PM -0500, Ben Myers wrote:
[...]
Quoted 8 lines
Quoted 2 lines
TODO: Store the unicode version number of the filesystem on disk in the super block.
So, if the filesystem has to store the specific unicode version it was created with so that we know what version to put in trie lookups, again I'll ask: why are we loading the trie as a generic kernel module and not as metadata in the filesystem that is demand paged and cached?
Quoted 6 lines
Quoted 2 lines
This way the trie can be shared, and the code using it is not entangled with the XFS code.
The trie parsing code can still be common - just the location and contents of the data is determined by the end-user.
Both these approaches can co-exists (as I recall was done in Windows). A system may have "a default trie" and a caller (name space) can provide its own...
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 15 lines · Dave Chinner
Quoted 14 lines · Olaf Weber
Quoted 1 line · Dave Chinner
On Thu, Sep 18, 2014 at 02:56:50PM -0500, Ben Myers wrote:
[...]
Quoted 8 lines
Quoted 2 lines
TODO: Store the unicode version number of the filesystem on disk in the super block.
So, if the filesystem has to store the specific unicode version it was created with so that we know what version to put in trie lookups, again I'll ask: why are we loading the trie as a generic kernel module and not as metadata in the filesystem that is demand paged and cached?
Quoted 5 lines
Quoted 2 lines
This way the trie can be shared, and the code using it is not entangled with the XFS code.
The trie parsing code can still be common - just the location and contents of the data is determined by the end-user.
I'm not sure how common the parsing code can be if needs to be capable of retrieving data from a filesystem.
Note given your and Andi Kleen's feedback on the trie size I've switched to doing algorithmic decomposition for Hangul. This reduces the size of the trie to 89952 bytes.
In addition, if you store the trie in the filesystem, then the only part that needs storing is the version for that particular filesystem, e.g no compatibility info for different unicode versions would be required. This would reduce the trie size to about 50kB for case-sensitive filesystems, and about 55kB on case-folding filesystems.
[...]
Quoted 10 lines
Quoted 9 lines
Quoted 4 lines
[...] Why should we let filesystems say "we fully understand and support utf8" and then allow them to accept and propagate invalid utf8 sequences and leave everyone else to have to clean up the mess?
Because the alternative amounts in my opinion to a demand that every bit of userspace that may be involved in generating filenames generate only clean UTF-8. I do not believe that this is a realistic demand at this point in time.
Quoted 4 lines
It's a chicken and egg situation. I'd much prefer we enforce clean utf8 from the start, because if we don't we'll never be able to do that. And other filesystems (e.g. ZFS) allow you to do reject anything that is not clean utf8....
As I understand it, this is optional in ZFS. I wonder what people's experiences are with this.
[...]
Quoted 11 lines
Quoted 10 lines
Quoted 5 lines
Yet normalised strings are only stable and hence comparable if there are no unassigned code points in them. What happens when userspace is not using the same version of unicode as the filesystem and is using newer code points in it's strings? Normalisation fails, right?
For the newer code points, yes. This is not treated as a failure to normalize the string as a whole, as there are clear guidelines in unicode on how unassigned code points interact with normalization:
they have canonical combining class 0 and no decomposition.
Quoted 6 lines
And so effectively are not stable. Which is something we absolutely have to avoid for information stored on disk. i.e. you're using the normalised form to build the hash values in the lookup index in the directory structure, and so having unstable normalisation forms is just wrong. Hence we'd need to reject anything with unassigned code points....
On a particular filesystem, the calculated normalization would be stable.
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
And as an extension of using normalisation for case-folded comparisons, how do we make case folding work with blobs that can't be normalised? It seems to me that this just leads to the nasty situation where some filenames are case sensitive and some aren't based on what the filesystem thinks is valid utf-8. The worst part is that userspace has no idea that the filesystem is making such distinctions and so behaviour is not at all predictable or expected.
Quoted 5 lines
Quoted 3 lines
Making case-folding work on a blob that cannot be normalized is (in my opinion) akin to doing an ASCII-based casefold on a Shift-JIS
string: the result is neither pretty nor useful.Yes, that's exactly my point.
But apparently we draw different conclusions from it.
Quoted 13 lines
Quoted 7 lines
Quoted 3 lines
This is another point in favour of rejecting invalid utf-8 strings and for keeping the translation tables stable within the filesystem...
Bear in mind that this means not just rejecting invalid UTF-8 strings, but also rejecting valid UTF-8 strings that encode unassigned code points.
And that's precisely what I'm suggesting: If we can't normalise the filename to a stable form then it cannot be used for hashing or case folding. That means it needs to be rejected, not treated as an opaque blob.
Quoted 5 lines
The moment we start parsing filenames they are no longer opaque blobs and so all existing "filename are opaque blobs" handling rules go out the window. They are now either valid so we can use them, or they are invalid and need to be rejected to avoid unpredictable and/or undesirable behaviour.
At this point I'd really like other people to weigh in on this and get a sense of how sentiment is spread on the question.
- Forbid non-UTF-8 filenames
- Allow non-UTF-8 filenames
- Make it a mount option
- Make it a mkfs option
[...]
Quoted 17 lines
Quoted 17 lines
Quoted 16 lines
Quoted 8 lines
The most contentious part is (should be) ignoring the codepoints with the
Default_Ignorable_Code_Pointproperty. I've included the list below. My argument, such as it is, is that these code points either have no visible rendering, or in cases like the soft hyphen, are only conditionally visible. The problem with these (as I see it) is that on seeing a filename that might contain them you cannot tell whether they are present. So I propose to ignore them for the purpose of comparing filenames for equality.Which introduces a non-standard "visibility criterial" for determining what should be or shouldn't be part of the normalised string for comparison. I don't see any real justification for stepping outside the standard unicode normalisation here - just because the user cannot see a character in a specific context does not mean that it is not significant to the application that created it.
Quoted 5 lines
Quoted 2 lines
I agree these characters may be significant to the application. I'm just not convinced that they should be significant in a file name.
They are significant to the case folding result, right? And therefore would be significant in a filename...
Case Folding doesn't affect the ignorables, so in that sense at least they're not significant to the case folding result, even if you do not ignore them.
[...]
Quoted 4 lines
Hence my comments about NLS integration. The NLS subsystem already has utf8 support with language dependent case folding tables. All the current filesystems that deal with unicode (including case folding) use the NLS subsystem for conversions.
Looking at the NLS subsystem I see support for translating a number of different encodings ("code pages") to unicode and back.
There is support for uppercase/lowercase translation for a number of those encodings. Which is not the same as language dependent case folding.
As for a unicode case fold, I see no support at all. In nls_utf8.c the uppercase/lowercase mappings are set to the identity maps.
I see no support for unicode normalization forms either.
Quoted 3 lines
Hmmm - looking at all the NLS code that does different utf format conversions first: what happens if an application is using UTF16 or UTF32 for it's filename encoding rather than utf8?
Since UTF-16 and UTF-32 strings contain embedded 0 bytes, those encodings cannot be used to pass a filename across the kernel/userspace interface.
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
Quoted 1 line
* XFS-specific design notes.
...
Quoted 4 lines
If the borgbit (the bit enabling legacy ASCII-based CI in XFS) is set in the superblock, then case folding is added into the mix. This is the nfkdicf normalization form mentioned above. It allows for the creation of case-insensitive filesystems with UTF-8 support.
Quoted 7 lines
Quoted 5 lines
Please don't overload existing superblock feature bits with multiple meanings. ASCII-CI is a stand-alone feature and is not in any way compatible with Unicode: Unicode-CI is a superset of Unicode support. So it really needs two new feature bits for Unicode and Unicode-CI, not just one for unicode.
It seemed an obvious extension of the meaning of that bit.
Quoted 10 lines
Feature bits refer to a specific on disk format feature. If that bit is set, then that feature is present. In this case, it means the filesystem is using ascii-ci. If that bit is passed out to userspace via the geometry ioctl, then *existing applications* expect it to mean ascii-ci behaviour from the filesystem. If an existing utility reads the flag field from disk (e.g. repair, metadump, db, etc) they all expect it to mean ascii-ci, and will do stuff based on that specific meaning. We cannot redefine the meaning of a feature bit after the fact - we have lots of feature bits so there's no need to overload an existing one for this.
Good point.
Quoted 3 lines
Hmmm - another interesting question just popped into my head about
metadump: file name obfuscation. What does unicode and utf8 mean for the hash collision calculation algorithm?
Good question.
Olaf
Signature · 9 lines
Olaf Weber SGI Phone: +31(0)30-6696796
Veldzigt 2b Fax: +31(0)30-6696799
Technical Lead 3454 PW de Meern Vnet: 955-6796
Storage Software The Netherlands Email: [email protected]
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfsQuoted 7 lines · Olaf Weber
I'm not sure how common the parsing code can be if needs to be capable of retrieving data from a filesystem.
Note given your and Andi Kleen's feedback on the trie size I've switched to doing algorithmic decomposition for Hangul. This reduces the size of the trie to 89952 bytes.
Quoted 5 lines
In addition, if you store the trie in the filesystem, then the only part that needs storing is the version for that particular filesystem, e.g no compatibility info for different unicode versions would be required. This would reduce the trie size to about 50kB for case-sensitive filesystems, and about 55kB on case-folding filesystems.
Honestly I wouldn't worry about demand loading it too much. This is a fairly special case code for NAS servers, and should not affect normal uses now that we use symbol_get. Let's get back to the fundamentals.
Quoted 7 lines
Quoted 4 lines
It's a chicken and egg situation. I'd much prefer we enforce clean utf8 from the start, because if we don't we'll never be able to do that. And other filesystems (e.g. ZFS) allow you to do reject anything that is not clean utf8....
As I understand it, this is optional in ZFS. I wonder what people's experiences are with this.
It is as optional as your utf8 support for XFS is. But they do enforce valid utf8 if they use utf8 normalization for file name comparisms, be that case sensitive or insensitive. Take a look at the zfs(8) man page.
Quoted 4 lines
- Forbid non-UTF-8 filenames
- Allow non-UTF-8 filenames
- Make it a mount option
- Make it a mkfs option
My take on this is:
- I think we'll have to prevent non-utf8 file names for any cases where we use utf8 normalization. If you do not use utf8 normalization it's plain old Unix everything is allowed.
- I think utf8 normalization vs not should be mkfs option, to make sure everyone including kernel and repair knows what sort of filesystem deal with.
- case insensitive matching for utf8 normalized filesystems should be a runtime decision. mount time for now, but Samba people would be extremly happy to allow per-operation or per-process CI matching. But that is another totally different discusion I'd like to keep separate, I just want to make sure the disk format allows for it for now.
Quoted 11 lines · Christoph Hellwig
My take on this is:
- I think we'll have to prevent non-utf8 file names for any cases where we use utf8 normalization. If you do not use utf8 normalization it's plain old Unix everything is allowed.
- I think utf8 normalization vs not should be mkfs option, to make sure everyone including kernel and repair knows what sort of filesystem deal with.
Quoted 6 lines
- case insensitive matching for utf8 normalized filesystems should be a runtime decision. mount time for now, but Samba people would be extremly happy to allow per-operation or per-process CI matching. But that is another totally different discusion I'd like to keep separate, I just want to make sure the disk format allows for it for now.
Actually, I'm so eager for case-insensitive matching I'd take "at format time", as with ZFS :-) :-).
Having CI matching can speed up Samba operations by a factor of 10 on large directories (warning, number made up, depending on the number of entries per dir :-).
Jeremy.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 2 lines · Jeremy Allison
Actually, I'm so eager for case-insensitive matching I'd take "at format time", as with ZFS :-) :-).
You already get this with XFS as long as you limit yourself to 7-bit ASCII :) And utf-8 with Olaf's patches as-is.
Maybe time to give them some testing?
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 6 lines · Christoph Hellwig
Quoted 2 lines · Jeremy Allison
Actually, I'm so eager for case-insensitive matching I'd take "at format time", as with ZFS :-) :-).
You already get this with XFS as long as you limit yourself to 7-bit ASCII :)
Thankyou for playing, here's a $10 gift token... No, that won't do I'm afraid :-).
Quoted 3 lines
And utf-8 with Olaf's patches as-is.
Maybe time to give them some testing?
I might do that, once I've finished rebuilding
my home server (remember kids, RAID5 is *NOT* a
backup :-) :-).
Quoted 19 lines · Jeremy Allison
Quoted 11 lines · Christoph Hellwig
My take on this is:
- I think we'll have to prevent non-utf8 file names for any cases where we use utf8 normalization. If you do not use utf8 normalization it's plain old Unix everything is allowed.
- I think utf8 normalization vs not should be mkfs option, to make sure everyone including kernel and repair knows what sort of filesystem deal with.
Quoted 6 lines
- case insensitive matching for utf8 normalized filesystems should be a runtime decision. mount time for now, but Samba people would be extremly happy to allow per-operation or per-process CI matching. But that is another totally different discusion I'd like to keep separate, I just want to make sure the disk format allows for it for now.
Quoted 2 lines
Actually, I'm so eager for case-insensitive matching I'd take "at format time", as with ZFS :-) :-).
My argument against "mount time case-insensitivity" and for "mkfs time case-insensitivity" is related to switching from the case-sensitive domain to the case-insensitive one.
For case-sensitive, from "README" to "readme" there are 64 different possible filenames. Let's say you create 63 out of these 64. Now remount the filesystem case-insensitive, and try to open by the 64th version of "readme". It is not an exact match for any of the 63 candidate files, and a case-insensitive match to all 63 candidate files. Which of these 63 files should be opened, and why that one in particular?
Quoted 3 lines
Having CI matching can speed up Samba operations by a factor of 10 on large directories (warning, number made up, depending on the number of entries per dir :-).
I really want that to be true, but the proof of the pudding...
Olaf
Signature · 9 lines
Olaf Weber SGI Phone: +31(0)30-6696796
Veldzigt 2b Fax: +31(0)30-6696799
Technical Lead 3454 PW de Meern Vnet: 955-6796
Storage Software The Netherlands Email: [email protected]
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfsQuoted 5 lines · Olaf Weber
My argument against "mount time case-insensitivity" and for "mkfs time case-insensitivity" is related to switching from the case-sensitive domain to the case-insensitive one.
Quoted 7 lines
For case-sensitive, from "README" to "readme" there are 64 different possible filenames. Let's say you create 63 out of these 64. Now remount the filesystem case-insensitive, and try to open by the 64th version of "readme". It is not an exact match for any of the 63 candidate files, and a case-insensitive match to all 63 candidate files. Which of these 63 files should be opened, and why that one in particular?
I'm ok with "mkfs time case-insensitivity" - really ! Most of my OEMs would set that and claim victory (few of them care much about NFS semantics :-).
Quoted 5 lines
Quoted 3 lines
Having CI matching can speed up Samba operations by a factor of 10 on large directories (warning, number made up, depending on the number of entries per dir :-).
I really want that to be true, but the proof of the pudding...
No it really *is* true. The reason I can't give exact numbers is it depends on the number of entries.
Remember, for every cache *miss*, we have to scan the entire directory.
So a user asks for README, and we attempt that and it fails. So now we have to enumerate the entire directory to see if READMe (or any other case varient) exists.
Now do that in a directory with 10, 100, 1000, .... 10000000 existing files (don't laugh, I've seen an application for Music files that did *exactly* that). On a case insensitive filesystem you just request README and you're done.
Certain vendors who shall remain nameless :-) created test cases of just this example to show how much storage on Linux sucks. Not
a happy camper about that - and telling them to use ZFS on FreeBSD or Solaris just doesn't feel right :-).
Jeremy.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 14 lines · Jeremy Allison
Quoted 5 lines · Olaf Weber
My argument against "mount time case-insensitivity" and for "mkfs time case-insensitivity" is related to switching from the case-sensitive domain to the case-insensitive one.
Quoted 7 lines
For case-sensitive, from "README" to "readme" there are 64 different possible filenames. Let's say you create 63 out of these 64. Now remount the filesystem case-insensitive, and try to open by the 64th version of "readme". It is not an exact match for any of the 63 candidate files, and a case-insensitive match to all 63 candidate files. Which of these 63 files should be opened, and why that one in particular?
Quoted 3 lines
I'm ok with "mkfs time case-insensitivity" - really ! Most of my OEMs would set that and claim victory (few of them care much about NFS semantics :-).
I'd say you can have CIFS-style case-insensitive semantics or NFS-style case-sensitive semantics, but not both. And in particular, that a customer should not actually want to have both.
Quoted 23 lines
Quoted 5 lines
Quoted 3 lines
Having CI matching can speed up Samba operations by a factor of 10 on large directories (warning, number made up, depending on the number of entries per dir :-).
I really want that to be true, but the proof of the pudding...
No it really *is* true. The reason I can't give exact numbers is it depends on the number of entries.
Remember, for every cache *miss*, we have to scan the entire directory.
So a user asks for README, and we attempt that and it fails. So now we have to enumerate the entire directory to see if READMe (or any other case varient) exists.
Now do that in a directory with 10, 100, 1000, .... 10000000 existing files (don't laugh, I've seen an application for Music files that did *exactly* that). On a case insensitive filesystem you just request README and you're done.
Quoted 6 lines
Certain vendors who shall remain nameless :-) created test cases of just this example to show how much storage on Linux sucks. Not
a happy camper about that - and telling them to use ZFS on FreeBSD or Solaris just doesn't feel right :-).
Here's the thing to bear in mind: what I did is a straightforward extension of the existing XFS ASCII-based case-insensitive code. If that gets you the desired performance improvement, then my code should extend that to more general usage. If it doesn't, then there are places in XFS that I haven't touched that need modification to have these cases work well.
Olaf
Signature · 9 lines
Olaf Weber SGI Phone: +31(0)30-6696796
Veldzigt 2b Fax: +31(0)30-6696799
Technical Lead 3454 PW de Meern Vnet: 955-6796
Storage Software The Netherlands Email: [email protected]
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfsQuoted 15 lines · Olaf Weber
Quoted 14 lines · Jeremy Allison
Quoted 12 lines · Olaf Weber
My argument against "mount time case-insensitivity" and for "mkfs time case-insensitivity" is related to switching from the case-sensitive domain to the case-insensitive one.
For case-sensitive, from "README" to "readme" there are 64 different possible filenames. Let's say you create 63 out of these 64. Now remount the filesystem case-insensitive, and try to open by the 64th version of "readme". It is not an exact match for any of the 63 candidate files, and a case-insensitive match to all 63 candidate files. Which of these 63 files should be opened, and why that one in particular?
Quoted 6 lines
Quoted 3 lines
I'm ok with "mkfs time case-insensitivity" - really ! Most of my OEMs would set that and claim victory (few of them care much about NFS semantics :-).
I'd say you can have CIFS-style case-insensitive semantics or NFS-style case-sensitive semantics, but not both.
Note the NFSv4 specs do claim to allow case insensitivity. No idea how well clients deal with it.
I think rfc3530bis has the most up to date language on NFSv4 internationalization issues:
http://tools.ietf.org/html/draft-ietf-nfsv4-rfc3530bis-33
(One nit in the current knfsd: the server doesn't correctly report the case_insensitive attribute. If it had some flag it could check in the filesystem's superblock then it could do that right instead of just assuming 0 as it currently does (see FATTR4_WORD0_CASE_INSENSITIVE in fs/nfsd/nfs4xdr.c:nfsd4_encode_fattr).)
--b.
Quoted 10 lines · Olaf Weber
My argument against "mount time case-insensitivity" and for "mkfs time case-insensitivity" is related to switching from the case-sensitive domain to the case-insensitive one.
For case-sensitive, from "README" to "readme" there are 64 different possible filenames. Let's say you create 63 out of these 64. Now remount the filesystem case-insensitive, and try to open by the 64th version of "readme". It is not an exact match for any of the 63 candidate files, and a case-insensitive match to all 63 candidate files. Which of these 63 files should be opened, and why that one in particular?
Well, the point is not that we use the CI-capable hash all the time. I fully expect the current XFS behavior to remain the default for normal systems forever. I just want to make sure that the CI implementation you chose can also allow mixed lookups if we desire.
Hey Christoph,
Quoted 6 lines · Christoph Hellwig
Quoted 5 lines · Olaf Weber
Quoted 4 lines
It's a chicken and egg situation. I'd much prefer we enforce clean utf8 from the start, because if we don't we'll never be able to do that. And other filesystems (e.g. ZFS) allow you to do reject anything that is not clean utf8....
Quoted 7 lines
Quoted 2 lines
As I understand it, this is optional in ZFS. I wonder what people's experiences are with this.
It is as optional as your utf8 support for XFS is. But they do enforce valid utf8 if they use utf8 normalization for file name comparisms, be that case sensitive or insensitive. Take a look at the zfs(8) man page.
The way I'm reading that man page, it seems like with ZFS you have one option to choose whether to use normalization:
'nomalization = "none|FormD|FormKCf"'
And a separate option to choose whether to accept non-utf8 filenames:
'utf8only = "on|off".
The default setting appears to be that ZFS does allow non-utf8 filenames.
Whereas with Olaf's series you have one option that turns normalization on or off, and he is not giving you a choice of whether non-utf8 filenames will be accepted (they will be accepted).
So IIUC there is a distinction: The utf8 support for ZFS is "more optional" than the utf8 support for XFS.
Regards,
Ben
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs