All of lore.kernel.org
 help / color / mirror / Atom feed
From: Barry Naujok <bnaujok@sgi.com>
To: xfs@oss.sgi.com
Cc: linux-fsdevel@vger.kernel.org
Subject: [PATCH 5/7] XFS: Unicode case-insensitive lookup implementation
Date: Wed, 02 Apr 2008 16:25:13 +1000	[thread overview]
Message-ID: <20080402062709.011126702@chook.melbourne.sgi.com> (raw)
In-Reply-To: 20080402062508.017738664@chook.melbourne.sgi.com

[-- Attachment #1: unicode_ci.patch --]
[-- Type: text/plain, Size: 41044 bytes --]

This is the core of the case-insensitive support - supporting and
enforcing UTF-8 (Unicode) filenames. All filename and user-level
extended attribute names are checked for UTF-8 compliance and the
hashes generated are always case-insensitive by utilising the
Unicode 5.0 standard case-folding table from:
http://www.unicode.org/Public/UNIDATA/CaseFolding.txt

As the hash is always case-insensitive, this allows the user to
mkfs.xfs the filesystem once and enable or disable (default)
case-insensitive support by a mount option "-o ci". The mount
option specifies which xfs_nameops.compname function to use.

Also, the Unicode support is a CONFIG option so users who do
not required this functionality can CONFIG it to N.

As the case-folding table is stored on disk, this allows
backwards and forwards compatibility and languages like Turkic
to support true case-insensitivity with I and i.

To create a Unicode filesystem with case-insensitive mount
support, run:
# mkfs.xfs -n utf8[=default|turkic] <device>

The final patches implement NLS support for XFS Unicode.

Signed-off-by: Barry Naujok <bnaujok@sgi.com>

---
 fs/xfs/Kconfig               |   17 +
 fs/xfs/Makefile              |    4 
 fs/xfs/linux-2.6/xfs_linux.h |    1 
 fs/xfs/linux-2.6/xfs_super.c |   14 +
 fs/xfs/linux-2.6/xfs_super.h |    7 
 fs/xfs/xfs_attr.c            |   24 ++
 fs/xfs/xfs_clnt.h            |    2 
 fs/xfs/xfs_da_btree.c        |   18 +
 fs/xfs/xfs_da_btree.h        |   16 -
 fs/xfs/xfs_dir2.c            |   13 -
 fs/xfs/xfs_dir2.h            |    5 
 fs/xfs/xfs_fs.h              |    1 
 fs/xfs/xfs_fsops.c           |    4 
 fs/xfs/xfs_itable.c          |    2 
 fs/xfs/xfs_mount.c           |   21 +
 fs/xfs/xfs_mount.h           |    7 
 fs/xfs/xfs_rename.c          |    9 
 fs/xfs/xfs_sb.h              |   29 ++
 fs/xfs/xfs_unicode.c         |  499 +++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_unicode.h         |   81 ++++++
 fs/xfs/xfs_vfsops.c          |   16 +
 fs/xfs/xfs_vnodeops.c        |   52 ++++
 22 files changed, 808 insertions(+), 34 deletions(-)

Index: kern_ci/fs/xfs/Kconfig
===================================================================
--- kern_ci.orig/fs/xfs/Kconfig
+++ kern_ci/fs/xfs/Kconfig
@@ -72,6 +72,21 @@ config XFS_POSIX_ACL
 
 	  If you don't know what Access Control Lists are, say N.
 
+config XFS_UNICODE
+	bool "XFS Unicode support"
+	depends on XFS_FS
+	help
+	  Unicode support enforces UTF-8 filenames and user extended
+	  attribute names. This option is required for filesystems
+	  mkfs'ed with UTF-8 support. A Unicode filesystem guarantees
+	  that filenames will be the same regardless of the user's
+	  locale. For UTF-8 locales, no conversion is required.
+
+	  Unicode filesystems also allow the filesystem to be mounted with
+	  case-insensitive lookup support with the "-o ci" mount option.
+
+	  If you don't require UTF-8 enforcement, say N.
+
 config XFS_RT
 	bool "XFS Realtime subvolume support"
 	depends on XFS_FS
@@ -107,7 +122,7 @@ config XFS_TRACE
 	bool "XFS Tracing support (EXPERIMENTAL)"
 	depends on XFS_FS && EXPERIMENTAL
 	help
-	  Say Y here to get an XFS build with activity tracing enabled.	
+	  Say Y here to get an XFS build with activity tracing enabled.
 	  Enabling this option will attach historical information to XFS
 	  inodes, buffers, certain locks, the log, the IO path, and a
 	  few other key areas within XFS.  These traces can be examined
Index: kern_ci/fs/xfs/Makefile
===================================================================
--- kern_ci.orig/fs/xfs/Makefile
+++ kern_ci/fs/xfs/Makefile
@@ -30,11 +30,11 @@ obj-$(CONFIG_XFS_DMAPI)		+= dmapi/
 
 xfs-$(CONFIG_XFS_RT)		+= xfs_rtalloc.o
 xfs-$(CONFIG_XFS_POSIX_ACL)	+= xfs_acl.o
+xfs-$(CONFIG_XFS_UNICODE)	+= xfs_unicode.o
 xfs-$(CONFIG_PROC_FS)		+= $(XFS_LINUX)/xfs_stats.o
 xfs-$(CONFIG_SYSCTL)		+= $(XFS_LINUX)/xfs_sysctl.o
 xfs-$(CONFIG_COMPAT)		+= $(XFS_LINUX)/xfs_ioctl32.o
 
-
 xfs-y				+= xfs_alloc.o \
 				   xfs_alloc_btree.o \
 				   xfs_attr.o \
@@ -97,7 +97,7 @@ xfs-y				+= $(addprefix $(XFS_LINUX)/, \
 				   xfs_lrw.o \
 				   xfs_super.o \
 				   xfs_vnode.o \
-				   xfs_ksyms.o) 
+				   xfs_ksyms.o)
 
 # Objects in support/
 xfs-y				+= $(addprefix support/, \
Index: kern_ci/fs/xfs/linux-2.6/xfs_linux.h
===================================================================
--- kern_ci.orig/fs/xfs/linux-2.6/xfs_linux.h
+++ kern_ci/fs/xfs/linux-2.6/xfs_linux.h
@@ -76,6 +76,7 @@
 #include <linux/log2.h>
 #include <linux/spinlock.h>
 #include <linux/ctype.h>
+#include <linux/nls.h>
 
 #include <asm/page.h>
 #include <asm/div64.h>
Index: kern_ci/fs/xfs/linux-2.6/xfs_super.c
===================================================================
--- kern_ci.orig/fs/xfs/linux-2.6/xfs_super.c
+++ kern_ci/fs/xfs/linux-2.6/xfs_super.c
@@ -46,6 +46,7 @@
 #include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
+#include "xfs_unicode.h"
 #include "xfs_utils.h"
 #include "xfs_vnodeops.h"
 #include "xfs_vfsops.h"
@@ -124,6 +125,7 @@ xfs_args_allocate(
 #define MNTOPT_ATTR2	"attr2"		/* do use attr2 attribute format */
 #define MNTOPT_NOATTR2	"noattr2"	/* do not use attr2 attribute format */
 #define MNTOPT_FILESTREAM  "filestreams" /* use filestreams allocator */
+#define MNTOPT_CILOOKUP	"ci"		/* case-insensitive dir lookup */
 #define MNTOPT_QUOTA	"quota"		/* disk quotas (user) */
 #define MNTOPT_NOQUOTA	"noquota"	/* no quotas */
 #define MNTOPT_USRQUOTA	"usrquota"	/* user quota enabled */
@@ -318,6 +320,14 @@ xfs_parseargs(
 			args->flags &= ~XFSMNT_ATTR2;
 		} else if (!strcmp(this_char, MNTOPT_FILESTREAM)) {
 			args->flags2 |= XFSMNT2_FILESTREAMS;
+		} else if (!strcmp(this_char, MNTOPT_CILOOKUP)) {
+			args->flags2 |= XFSMNT2_CILOOKUP;
+#ifndef CONFIG_XFS_UNICODE
+			cmn_err(CE_WARN,
+				"XFS: %s option requires Unicode support",
+				this_char);
+			return EINVAL;
+#endif
 		} else if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
 			args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA);
 			args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA);
@@ -458,6 +468,7 @@ xfs_showargs(
 		{ XFS_MOUNT_OSYNCISOSYNC,	"," MNTOPT_OSYNCISOSYNC },
 		{ XFS_MOUNT_ATTR2,		"," MNTOPT_ATTR2 },
 		{ XFS_MOUNT_FILESTREAMS,	"," MNTOPT_FILESTREAM },
+		{ XFS_MOUNT_CILOOKUP,		"," MNTOPT_CILOOKUP },
 		{ XFS_MOUNT_DMAPI,		"," MNTOPT_DMAPI },
 		{ XFS_MOUNT_GRPID,		"," MNTOPT_GRPID },
 		{ 0, NULL }
@@ -567,7 +578,8 @@ xfs_set_inodeops(
 		break;
 	case S_IFDIR:
 		inode->i_op =
-			xfs_sb_version_hasoldci(&XFS_I(inode)->i_mount->m_sb) ?
+			xfs_sb_version_hasoldci(&XFS_I(inode)->i_mount->m_sb) ||
+			(XFS_I(inode)->i_mount->m_flags & XFS_MOUNT_CILOOKUP) ?
 				&xfs_dir_ci_inode_operations :
 				&xfs_dir_inode_operations;
 		inode->i_fop = &xfs_dir_file_operations;
Index: kern_ci/fs/xfs/linux-2.6/xfs_super.h
===================================================================
--- kern_ci.orig/fs/xfs/linux-2.6/xfs_super.h
+++ kern_ci/fs/xfs/linux-2.6/xfs_super.h
@@ -36,6 +36,12 @@
 # define ENOSECURITY		EOPNOTSUPP
 #endif
 
+#ifdef CONFIG_XFS_UNICODE
+# define XFS_UNICODE_STRING	"Unicode, "
+#else
+# define XFS_UNICODE_STRING
+#endif
+
 #ifdef CONFIG_XFS_RT
 # define XFS_REALTIME_STRING	"realtime, "
 #else
@@ -66,6 +72,7 @@
 
 #define XFS_BUILD_OPTIONS	XFS_ACL_STRING \
 				XFS_SECURITY_STRING \
+				XFS_UNICODE_STRING \
 				XFS_REALTIME_STRING \
 				XFS_BIGFS_STRING \
 				XFS_TRACE_STRING \
Index: kern_ci/fs/xfs/xfs_attr.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_attr.c
+++ kern_ci/fs/xfs/xfs_attr.c
@@ -50,6 +50,7 @@
 #include "xfs_acl.h"
 #include "xfs_rw.h"
 #include "xfs_vnodeops.h"
+#include "xfs_unicode.h"
 
 /*
  * xfs_attr.c
@@ -175,6 +176,13 @@ xfs_attr_get(
 	if (namelen >= MAXNAMELEN)
 		return(EFAULT);		/* match IRIX behaviour */
 
+	/* Enforce UTF-8 only for user attr names */
+	if (xfs_sb_version_hasunicode(&ip->i_mount->m_sb) &&
+			(flags & (ATTR_ROOT | ATTR_SECURE)) == 0) {
+		error = xfs_unicode_validate(name, namelen);
+		if (error)
+			return error;
+	}
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		return(EIO);
 
@@ -435,6 +443,14 @@ xfs_attr_set(
 	if (namelen >= MAXNAMELEN)
 		return EFAULT;		/* match IRIX behaviour */
 
+	/* Enforce UTF-8 only for user attr names */
+	if (xfs_sb_version_hasunicode(&dp->i_mount->m_sb) &&
+			(flags & (ATTR_ROOT | ATTR_SECURE)) == 0) {
+		int error = xfs_unicode_validate(name, namelen);
+		if (error)
+			return error;
+	}
+
 	XFS_STATS_INC(xs_attr_set);
 
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
@@ -581,6 +597,14 @@ xfs_attr_remove(
 	if (namelen >= MAXNAMELEN)
 		return EFAULT;		/* match IRIX behaviour */
 
+	/* Enforce UTF-8 only for user attr names */
+	if (xfs_sb_version_hasunicode(&dp->i_mount->m_sb) &&
+			(flags & (ATTR_ROOT | ATTR_SECURE)) == 0) {
+		int error = xfs_unicode_validate(name, namelen);
+		if (error)
+			return error;
+	}
+
 	XFS_STATS_INC(xs_attr_remove);
 
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
Index: kern_ci/fs/xfs/xfs_clnt.h
===================================================================
--- kern_ci.orig/fs/xfs/xfs_clnt.h
+++ kern_ci/fs/xfs/xfs_clnt.h
@@ -100,5 +100,7 @@ struct xfs_mount_args {
 						 * I/O size in stat(2) */
 #define XFSMNT2_FILESTREAMS	0x00000002	/* enable the filestreams
 						 * allocator */
+#define XFSMNT2_CILOOKUP	0x00000004	/* enable case-insensitive
+						 * filename lookup */
 
 #endif	/* __XFS_CLNT_H__ */
Index: kern_ci/fs/xfs/xfs_da_btree.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_da_btree.c
+++ kern_ci/fs/xfs/xfs_da_btree.c
@@ -1530,16 +1530,22 @@ xfs_da_hashname(const uchar_t *name, int
 	}
 }
 
-xfs_dacmp_t
-xfs_da_compname(const uchar_t *name1, int len1, const uchar_t *name2, int len2)
+static xfs_dahash_t
+xfs_default_hashname(xfs_inode_t *inode, const uchar_t *name, int namelen)
 {
-	return (len1 == len2 && memcmp(name1, name2, len1) == 0) ?
-			XFS_CMP_EXACT : XFS_CMP_DIFFERENT;
+	return xfs_da_hashname(name, namelen);
+}
+
+static xfs_dacmp_t
+xfs_default_compname(xfs_inode_t *inode, const uchar_t *name1, int namelen1,
+		     const uchar_t *name2, int namelen2)
+{
+	return xfs_da_compname(name1, namelen1, name2, namelen2);
 }
 
 struct xfs_nameops xfs_default_nameops = {
-	.hashname	= xfs_da_hashname,
-	.compname	= xfs_da_compname
+	.hashname	= xfs_default_hashname,
+	.compname	= xfs_default_compname
 };
 
 /*
Index: kern_ci/fs/xfs/xfs_da_btree.h
===================================================================
--- kern_ci.orig/fs/xfs/xfs_da_btree.h
+++ kern_ci/fs/xfs/xfs_da_btree.h
@@ -215,9 +215,10 @@ typedef struct xfs_da_state {
  * Name ops for directory and/or attr name operations
  */
 
-typedef xfs_dahash_t	(*xfs_hashname_t)(const uchar_t *, int);
-typedef xfs_dacmp_t	(*xfs_compname_t)(const uchar_t *, int,
-					  const uchar_t *, int);
+typedef xfs_dahash_t	(*xfs_hashname_t)(struct xfs_inode *, const uchar_t *,
+					  int);
+typedef xfs_dacmp_t	(*xfs_compname_t)(struct xfs_inode *, const uchar_t *,
+					  int, const uchar_t *, int);
 
 typedef struct xfs_nameops {
 	xfs_hashname_t		hashname;
@@ -282,8 +283,13 @@ int	xfs_da_shrink_inode(xfs_da_args_t *a
 extern struct xfs_nameops xfs_default_nameops;
 
 uint xfs_da_hashname(const uchar_t *name_string, int name_length);
-xfs_dacmp_t xfs_da_compname(const uchar_t *name1, int len1,
-			    const uchar_t *name2, int len2);
+
+static inline xfs_dacmp_t
+xfs_da_compname(const uchar_t *name1, int len1, const uchar_t *name2, int len2)
+{
+	return (len1 == len2 && memcmp(name1, name2, len1) == 0) ?
+			XFS_CMP_EXACT : XFS_CMP_DIFFERENT;
+}
 
 /* returns/frees a MAXNAMELEN buffer from a zone */
 extern struct kmem_zone *xfs_da_name_zone;
Index: kern_ci/fs/xfs/xfs_dir2.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_dir2.c
+++ kern_ci/fs/xfs/xfs_dir2.c
@@ -43,7 +43,7 @@
 #include "xfs_dir2_trace.h"
 #include "xfs_error.h"
 #include "xfs_vnodeops.h"
-
+#include "xfs_unicode.h"
 
 /*
  * V1/OLDCI case-insensitive support for directories
@@ -52,6 +52,7 @@
  */
 static xfs_dahash_t
 xfs_ascii_ci_hashname(
+	xfs_inode_t	*inode,
 	const uchar_t	*name,
 	int		namelen)
 {
@@ -66,6 +67,7 @@ xfs_ascii_ci_hashname(
 
 static xfs_dacmp_t
 xfs_ascii_ci_compname(
+	xfs_inode_t	*inode,
 	const uchar_t	*name1,
 	int		len1,
 	const uchar_t	*name2,
@@ -113,8 +115,13 @@ xfs_dir_mount(
 		(mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
 		(uint)sizeof(xfs_da_node_entry_t);
 	mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
-	mp->m_dirnameops = xfs_sb_version_hasoldci(&mp->m_sb) ?
-		&xfs_ascii_ci_nameops : &xfs_default_nameops;
+
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		mp->m_dirnameops = (mp->m_flags & XFS_MOUNT_CILOOKUP) ?
+			&xfs_unicode_ci_nameops : &xfs_unicode_nameops;
+	} else
+		mp->m_dirnameops = xfs_sb_version_hasoldci(&mp->m_sb) ?
+			&xfs_ascii_ci_nameops : &xfs_default_nameops;
 }
 
 /*
Index: kern_ci/fs/xfs/xfs_dir2.h
===================================================================
--- kern_ci.orig/fs/xfs/xfs_dir2.h
+++ kern_ci/fs/xfs/xfs_dir2.h
@@ -88,10 +88,11 @@ extern int xfs_dir_canenter(struct xfs_t
 extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
 
 #define xfs_dir_hashname(dp, n, l) \
-		((dp)->i_mount->m_dirnameops->hashname((n), (l)))
+		((dp)->i_mount->m_dirnameops->hashname((dp), (n), (l)))
 
 #define xfs_dir_compname(dp, n1, l1, n2, l2) \
-		((dp)->i_mount->m_dirnameops->compname((n1), (l1), (n2), (l2)))
+		((dp)->i_mount->m_dirnameops->compname((dp), (n1), (l1), \
+							(n2), (l2)))
 
 /*
  * Utility routines for v2 directories.
Index: kern_ci/fs/xfs/xfs_fs.h
===================================================================
--- kern_ci.orig/fs/xfs/xfs_fs.h
+++ kern_ci/fs/xfs/xfs_fs.h
@@ -241,6 +241,7 @@ typedef struct xfs_fsop_resblks {
 #define XFS_FSOP_GEOM_FLAGS_ATTR2	0x0400	/* inline attributes rework */
 #define XFS_FSOP_GEOM_FLAGS_DIRV2CI	0x1000	/* ASCII only CI names */
 #define XFS_FSOP_GEOM_FLAGS_LAZYSB	0x4000	/* lazy superblock counters */
+#define XFS_FSOP_GEOM_FLAGS_UNICODE	0x10000	/* unicode filenames */
 
 
 /*
Index: kern_ci/fs/xfs/xfs_fsops.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_fsops.c
+++ kern_ci/fs/xfs/xfs_fsops.c
@@ -100,7 +100,9 @@ xfs_fs_geometry(
 			(xfs_sb_version_haslazysbcount(&mp->m_sb) ?
 				XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) |
 			(xfs_sb_version_hasattr2(&mp->m_sb) ?
-				XFS_FSOP_GEOM_FLAGS_ATTR2 : 0);
+				XFS_FSOP_GEOM_FLAGS_ATTR2 : 0) |
+			(xfs_sb_version_hasunicode(&mp->m_sb) ?
+				XFS_FSOP_GEOM_FLAGS_UNICODE : 0);
 		geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
 				mp->m_sb.sb_logsectsize : BBSIZE;
 		geo->rtsectsize = mp->m_sb.sb_blocksize;
Index: kern_ci/fs/xfs/xfs_itable.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_itable.c
+++ kern_ci/fs/xfs/xfs_itable.c
@@ -45,6 +45,8 @@ xfs_internal_inum(
 	xfs_ino_t	ino)
 {
 	return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
+		(xfs_sb_version_hasunicode(&mp->m_sb) &&
+		 ino == mp->m_sb.sb_cftino) ||
 		(xfs_sb_version_hasquota(&mp->m_sb) &&
 		 (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino)));
 }
Index: kern_ci/fs/xfs/xfs_mount.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_mount.c
+++ kern_ci/fs/xfs/xfs_mount.c
@@ -44,6 +44,7 @@
 #include "xfs_quota.h"
 #include "xfs_fsops.h"
 #include "xfs_utils.h"
+#include "xfs_unicode.h"
 
 STATIC void	xfs_mount_log_sb(xfs_mount_t *, __int64_t);
 STATIC int	xfs_uuid_mount(xfs_mount_t *);
@@ -121,6 +122,7 @@ static const struct {
     { offsetof(xfs_sb_t, sb_logsunit),	 0 },
     { offsetof(xfs_sb_t, sb_features2),	 0 },
     { offsetof(xfs_sb_t, sb_bad_features2), 0 },
+    { offsetof(xfs_sb_t, sb_cftino),	 0 },
     { sizeof(xfs_sb_t),			 0 }
 };
 
@@ -167,6 +169,7 @@ xfs_mount_free(
 			  sizeof(xfs_perag_t) * mp->m_sb.sb_agcount);
 	}
 
+	xfs_unicode_free_cft(mp->m_cft);
 	spinlock_destroy(&mp->m_ail_lock);
 	spinlock_destroy(&mp->m_sb_lock);
 	mutex_destroy(&mp->m_ilock);
@@ -452,6 +455,7 @@ xfs_sb_from_disk(
 	to->sb_logsunit = be32_to_cpu(from->sb_logsunit);
 	to->sb_features2 = be32_to_cpu(from->sb_features2);
 	to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2);
+	to->sb_cftino = be64_to_cpu(from->sb_cftino);
 }
 
 /*
@@ -1175,6 +1179,18 @@ xfs_mountfs(
 	}
 
 	/*
+	 * Load in unicode case folding table from disk
+	 */
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		error = xfs_unicode_read_cft(mp);
+		if (error) {
+			cmn_err(CE_WARN,
+				"XFS: failed to read case folding table");
+			goto error4;
+		}
+	}
+
+	/*
 	 * If fs is not mounted readonly, then update the superblock changes.
 	 */
 	if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY))
@@ -1229,7 +1245,8 @@ xfs_mountfs(
 	 * Free up the root inode.
 	 */
 	IRELE(rip);
- error3:
+	xfs_unicode_free_cft(mp->m_cft);
+error3:
 	xfs_log_unmount_dealloc(mp);
  error2:
 	for (agno = 0; agno < sbp->sb_agcount; agno++)
@@ -1956,7 +1973,7 @@ xfs_mount_log_sb(
  * 	3. accurate counter sync requires m_sb_lock + per cpu locks
  * 	4. modifying per-cpu counters requires holding per-cpu lock
  * 	5. modifying global counters requires holding m_sb_lock
- *	6. enabling or disabling a counter requires holding the m_sb_lock 
+ *	6. enabling or disabling a counter requires holding the m_sb_lock
  *	   and _none_ of the per-cpu locks.
  *
  * Disabled counters are only ever re-enabled by a balance operation
Index: kern_ci/fs/xfs/xfs_mount.h
===================================================================
--- kern_ci.orig/fs/xfs/xfs_mount.h
+++ kern_ci/fs/xfs/xfs_mount.h
@@ -62,6 +62,7 @@ struct xfs_extdelta;
 struct xfs_swapext;
 struct xfs_mru_cache;
 struct xfs_nameops;
+struct xfs_cft;
 
 /*
  * Prototypes and functions for the Data Migration subsystem.
@@ -314,6 +315,7 @@ typedef struct xfs_mount {
 						   field governed by m_ilock */
 	__uint8_t		m_sectbb_log;	/* sectlog - BBSHIFT */
 	struct xfs_nameops	*m_dirnameops;	/* vector of dir name ops */
+	struct xfs_cft		*m_cft;		/* unicode case fold table */
 	int			m_dirblksize;	/* directory block sz--bytes */
 	int			m_dirblkfsbs;	/* directory block sz--fsbs */
 	xfs_dablk_t		m_dirdatablk;	/* blockno of dir data v2 */
@@ -379,7 +381,8 @@ typedef struct xfs_mount {
 						   counters */
 #define XFS_MOUNT_FILESTREAMS	(1ULL << 24)	/* enable the filestreams
 						   allocator */
-
+#define XFS_MOUNT_CILOOKUP	(1ULL << 25)	/* enable case-insensitive
+						   file lookup */
 
 /*
  * Default minimum read and write sizes.
@@ -403,7 +406,7 @@ typedef struct xfs_mount {
 
 /*
  * Allow large block sizes to be reported to userspace programs if the
- * "largeio" mount option is used. 
+ * "largeio" mount option is used.
  *
  * If compatibility mode is specified, simply return the basic unit of caching
  * so that we don't get inefficient read/modify/write I/O from user apps.
Index: kern_ci/fs/xfs/xfs_rename.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_rename.c
+++ kern_ci/fs/xfs/xfs_rename.c
@@ -39,6 +39,7 @@
 #include "xfs_utils.h"
 #include "xfs_trans_space.h"
 #include "xfs_vnodeops.h"
+#include "xfs_unicode.h"
 
 
 /*
@@ -248,6 +249,14 @@ xfs_rename(
 	xfs_itrace_entry(src_dp);
 	xfs_itrace_entry(target_dp);
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		error = xfs_unicode_validate(src_name, src_namelen);
+		if (error)
+			return error;
+		error = xfs_unicode_validate(target_name, target_namelen);
+		if (error)
+			return error;
+	}
 	if (DM_EVENT_ENABLED(src_dp, DM_EVENT_RENAME) ||
 	    DM_EVENT_ENABLED(target_dp, DM_EVENT_RENAME)) {
 		error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME,
Index: kern_ci/fs/xfs/xfs_sb.h
===================================================================
--- kern_ci.orig/fs/xfs/xfs_sb.h
+++ kern_ci/fs/xfs/xfs_sb.h
@@ -79,10 +79,18 @@ struct xfs_mount;
 #define XFS_SB_VERSION2_LAZYSBCOUNTBIT	0x00000002	/* Superblk counters */
 #define XFS_SB_VERSION2_RESERVED4BIT	0x00000004
 #define XFS_SB_VERSION2_ATTR2BIT	0x00000008	/* Inline attr rework */
+#define XFS_SB_VERSION2_UNICODEBIT	0x00000020	/* Unicode names */
 
-#define	XFS_SB_VERSION2_OKREALFBITS	\
+#ifdef CONFIG_XFS_UNICODE
+# define XFS_SB_VERSION2_OKREALFBITS	\
 	(XFS_SB_VERSION2_LAZYSBCOUNTBIT	| \
+	 XFS_SB_VERSION2_UNICODEBIT | \
 	 XFS_SB_VERSION2_ATTR2BIT)
+#else
+# define XFS_SB_VERSION2_OKREALFBITS	\
+	(XFS_SB_VERSION2_LAZYSBCOUNTBIT	| \
+	 XFS_SB_VERSION2_ATTR2BIT)
+#endif
 #define	XFS_SB_VERSION2_OKSASHFBITS	\
 	(0)
 #define XFS_SB_VERSION2_OKREALBITS	\
@@ -156,6 +164,7 @@ typedef struct xfs_sb {
 	 * it for anything else.
 	 */
 	__uint32_t	sb_bad_features2;
+	xfs_ino_t	sb_cftino;	/* unicode case folding table inode */
 
 	/* must be padded to 64 bit alignment */
 } xfs_sb_t;
@@ -225,7 +234,8 @@ typedef struct xfs_dsb {
 	 * for features2 bits. Easiest just to mark it bad and not use
 	 * it for anything else.
 	 */
-	__be32	sb_bad_features2;
+	__be32		sb_bad_features2;
+	__be64		sb_cftino;	/* unicode case folding table inode */
 
 	/* must be padded to 64 bit alignment */
 } xfs_dsb_t;
@@ -246,7 +256,7 @@ typedef enum {
 	XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
 	XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
 	XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
-	XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
+	XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2, XFS_SBS_CFTINO,
 	XFS_SBS_FIELDCOUNT
 } xfs_sb_field_t;
 
@@ -272,6 +282,7 @@ typedef enum {
 #define XFS_SB_FDBLOCKS		XFS_SB_MVAL(FDBLOCKS)
 #define XFS_SB_FEATURES2	XFS_SB_MVAL(FEATURES2)
 #define XFS_SB_BAD_FEATURES2	XFS_SB_MVAL(BAD_FEATURES2)
+#define XFS_SB_CFTINO		XFS_SB_MVAL(CFTINO)
 #define	XFS_SB_NUM_BITS		((int)XFS_SBS_FIELDCOUNT)
 #define	XFS_SB_ALL_BITS		((1LL << XFS_SB_NUM_BITS) - 1)
 #define	XFS_SB_MOD_BITS		\
@@ -279,7 +290,7 @@ typedef enum {
 	 XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
 	 XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
 	 XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
-	 XFS_SB_BAD_FEATURES2)
+	 XFS_SB_BAD_FEATURES2 | XFS_SB_CFTINO)
 
 
 /*
@@ -480,6 +491,16 @@ static inline void xfs_sb_version_addatt
 		((sbp)->sb_features2 | XFS_SB_VERSION2_ATTR2BIT)));
 }
 
+#ifdef CONFIG_XFS_UNICODE
+static inline int xfs_sb_version_hasunicode(xfs_sb_t *sbp)
+{
+	return (xfs_sb_version_hasmorebits(sbp) &&	\
+		((sbp)->sb_features2 & XFS_SB_VERSION2_UNICODEBIT));
+}
+#else
+# define xfs_sb_version_hasunicode(sbp)	(0)
+#endif
+
 /*
  * end of superblock version macros
  */
Index: kern_ci/fs/xfs/xfs_unicode.c
===================================================================
--- /dev/null
+++ kern_ci/fs/xfs/xfs_unicode.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2007-2008 Silicon Graphics, Inc.
+ * 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
+ */
+
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_bit.h"
+#include "xfs_log.h"
+#include "xfs_inum.h"
+#include "xfs_clnt.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_da_btree.h"
+#include "xfs_dir2.h"
+#include "xfs_alloc.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_dir2_sf.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_itable.h"
+#include "xfs_rtalloc.h"
+#include "xfs_error.h"
+#include "xfs_bmap.h"
+#include "xfs_rw.h"
+#include "xfs_unicode.h"
+
+#define MAX_FOLD_CHARS	4
+
+static inline int
+xfs_casefold(
+	const xfs_cft_t *cft,
+	__uint16_t	c,
+	__uint16_t	*fc)
+{
+	__uint16_t	*table = XFS_CFT_PTR(cft, 0);
+	__uint16_t	tmp = table[c >> 8];
+	int		i;
+
+	if (!tmp) {
+		*fc = c;
+		return 1;
+	}
+	tmp = table[tmp + (c & 0xff)];
+	if ((tmp & 0xf000) != 0xe000) {
+		*fc = tmp;
+		return 1;
+	}
+	i = ((tmp >> 10) & 0x3) + 2;
+	ASSERT(i < cft->num_tables);
+	table = XFS_CFT_PTR(cft, i - 1) + ((tmp & 0x3ff) * i);
+
+	memcpy(fc, table, sizeof(__uint16_t) * i);
+
+	return i;
+}
+
+static inline int
+xfs_utf8_casefold(
+	const xfs_cft_t	*cft,
+	const uchar_t	**name,
+	int		*namelen,
+	__uint16_t	*fc)
+{
+	wchar_t		uc;
+
+	if (*namelen == 0)
+		return 0;
+
+	if (**name & 0x80) {
+		int	n = utf8_mbtowc(&uc, *name, *namelen);
+		if (n < 0) {
+			(*namelen)--;
+			*fc = *(*name)++;
+			return 1;
+		}
+		*name += n;
+		*namelen -= n;
+	} else {
+		uc = *(*name)++;
+		(*namelen)--;
+	}
+	return xfs_casefold(cft, uc, fc);
+}
+
+/*
+ * always generate a case-folded hash to allow mount-time selection of
+ * case-insensitive lookup (rather than mkfs time).
+ */
+xfs_dahash_t
+xfs_unicode_hashname(
+	xfs_inode_t	*inode,
+	const uchar_t	*name,
+	int		namelen)
+{
+	xfs_dahash_t	hash = 0;
+	__uint16_t	fc[MAX_FOLD_CHARS];
+	int		nfc;
+	int		i;
+
+	while (namelen > 0) {
+		nfc = xfs_utf8_casefold(inode->i_mount->m_cft, &name, &namelen,
+				fc);
+		for (i = 0; i < nfc; i++)
+			hash = fc[i] ^ rol32(hash, 7);
+	}
+	return hash;
+}
+
+/*
+ * Perform a case-folding case-insensitive string comparison,
+ * returns either XFS_CMP_CASE or XFS_CMP_DIFFERENT.
+ */
+static xfs_dacmp_t
+xfs_unicode_casecmp(
+	xfs_cft_t	*cft,
+	const uchar_t	*name1,
+	int		len1,
+	const uchar_t	*name2,
+	int		len2)
+{
+	__uint16_t	fc1[MAX_FOLD_CHARS], fc2[MAX_FOLD_CHARS];
+	__uint16_t	*pfc1, *pfc2;
+	int		nfc1, nfc2;
+
+	nfc1 = xfs_utf8_casefold(cft, &name1, &len1, fc1);
+	pfc1 = fc1;
+	nfc2 = xfs_utf8_casefold(cft, &name2, &len2, fc2);
+	pfc2 = fc2;
+
+	while (nfc1 > 0 && nfc2 > 0) {
+		if (*pfc1 != *pfc2)
+			return XFS_CMP_DIFFERENT;
+		if (!--nfc1) {
+			nfc1 = xfs_utf8_casefold(cft, &name1, &len1, fc1);
+			pfc1 = fc1;
+		} else
+			pfc1++;
+		if (!--nfc2) {
+			nfc2 = xfs_utf8_casefold(cft, &name2, &len2, fc2);
+			pfc2 = fc2;
+		} else
+			pfc2++;
+	}
+	if (nfc1 != nfc2)
+		return XFS_CMP_DIFFERENT;
+	return XFS_CMP_CASE;
+
+}
+
+/*
+ * Compare two UTF-8 names to see if they are exactly the same or
+ * case-insensitive match.
+ */
+xfs_dacmp_t
+xfs_unicode_compname(
+	xfs_inode_t	*inode,
+	const uchar_t	*name1,
+	int		len1,
+	const uchar_t	*name2,
+	int		len2)
+{
+	wchar_t		uc1, uc2;
+	int		n;
+
+	/*
+	 * If the lengths are different, go straight to the case-insensitive
+	 * comparison
+	 */
+	if (len1 != len2)
+		return xfs_unicode_casecmp(inode->i_mount->m_cft,
+					name1, len1, name2, len2);
+
+	/*
+	 * Start by comparing one-to-one UTF-8 chars. If we have a mismatch,
+	 * downgrade to case-insensitive comparison on the rest of the names.
+	 * At this stage, we only need to maintain one length variable.
+	 */
+	while (len1) {
+		/*
+		 * first do a direct compare, if different, try the
+		 * case-insensitive comparison on the remainder.
+		 */
+		if (*name1 != *name2)
+			return xfs_unicode_casecmp(inode->i_mount->m_cft,
+						name1, len1, name2, len1);
+		/*
+		 * if we are working on a UTF-8 sequence, take in all
+		 * appropriate chars and then compare.
+		 */
+		if (*name1 >= 0x80) {
+			n = utf8_mbtowc(&uc1, name1, len1);
+			if (n < 0)
+				return XFS_CMP_DIFFERENT; /* invalid */
+			utf8_mbtowc(&uc2, name2, len1);
+			/*
+			 * no need to check "n" here as the first char
+			 * determines the length of a UTF-8 sequence.
+			 */
+			if (uc1 != uc2)
+				return xfs_unicode_casecmp(
+						inode->i_mount->m_cft,
+						name1, len1, name2, len1);
+		} else {
+			n = 1;
+		}
+		name1 += n;
+		name2 += n;
+		len1 -= n;
+	}
+	/*
+	 * to get here, all chars must have matched
+	 */
+	return XFS_CMP_EXACT;
+}
+
+static xfs_dacmp_t
+xfs_default_compname(
+	xfs_inode_t	*inode,
+	const uchar_t	*name1,
+	int		namelen1,
+	const uchar_t	*name2,
+	int		namelen2)
+{
+	return xfs_da_compname(name1, namelen1, name2, namelen2);
+}
+
+struct xfs_nameops xfs_unicode_nameops = {
+	.hashname	= xfs_unicode_hashname,
+	.compname	= xfs_default_compname,
+};
+
+struct xfs_nameops xfs_unicode_ci_nameops = {
+	.hashname	= xfs_unicode_hashname,
+	.compname	= xfs_unicode_compname,
+};
+
+int
+xfs_unicode_validate(
+	const uchar_t	*name,
+	int		namelen)
+{
+	wchar_t		uc;
+	int		i, nlen;
+
+	for (i = 0; i < namelen; i += nlen) {
+		if (*name >= 0xf0) {
+			cmn_err(CE_WARN, "xfs_unicode_validate: "
+					"UTF-8 char beyond U+FFFF\n");
+			return EINVAL;
+		}
+		/* utf8_mbtowc must fail on overlong sequences too */
+		nlen = utf8_mbtowc(&uc, name + i, namelen - i);
+		if (nlen < 0) {
+			cmn_err(CE_WARN, "xfs_unicode_validate: "
+					"invalid UTF-8 sequence\n");
+			return EILSEQ;
+		}
+		/* check for invalid/surrogate/private unicode chars */
+		if (uc >= 0xfffe || (uc >= 0xd800 && uc <= 0xf8ff)) {
+			cmn_err(CE_WARN, "xfs_unicode_validate: "
+					"unsupported UTF-8 char\n");
+			return EINVAL;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Unicode Case Fold Table management
+ */
+
+struct cft_item {
+	xfs_cft_t	*table;
+	int		size;
+	int		refcount;
+};
+
+static mutex_t		cft_lock;
+static int		cft_size;
+static struct cft_item	*cft_list;
+
+static xfs_cft_t *
+add_cft(
+	xfs_dcft_t	*dcft,
+	int		size)
+{
+	int		found = 0;
+	int		i, j;
+	xfs_cft_t	*cft;
+	__be16		*duc;
+	__uint16_t	*uc;
+
+	mutex_lock(&cft_lock);
+
+	for (i = 0; i < cft_size; i++) {
+		if (cft_list[i].size != size)
+			continue;
+		cft = cft_list[i].table;
+		if (cft->num_tables != be32_to_cpu(dcft->num_tables) ||
+				cft->flags != be32_to_cpu(dcft->flags))
+			continue;
+		found = 1;
+		for (j = 0; j < cft->num_tables; j++) {
+			if (cft->table_offset[j] !=
+					be32_to_cpu(dcft->table_offset[j])) {
+				found = 0;
+				break;
+			}
+		}
+		if (found) {
+			cft_list[i].refcount++;
+			mutex_unlock(&cft_lock);
+			return cft;
+		}
+	}
+
+	cft = vmalloc(size);
+	if (!cft) {
+		mutex_unlock(&cft_lock);
+		return NULL;
+	}
+	cft->magic = be32_to_cpu(dcft->magic);
+	cft->flags = be32_to_cpu(dcft->flags);
+	cft->num_tables = be32_to_cpu(dcft->num_tables);
+	ASSERT(cft->num_tables <= MAX_FOLD_CHARS);
+	for (i = 0; i < cft->num_tables; i++)
+		cft->table_offset[i] = be32_to_cpu(dcft->table_offset[i]);
+	j = (size - cft->table_offset[0]) / sizeof(__uint16_t);
+	uc = XFS_CFT_PTR(cft, 0);
+	duc = XFS_DCFT_PTR(dcft, 0);
+	for (i = 0; i < j; i++)
+		uc[i] = be16_to_cpu(duc[i]);
+
+	cft_list = kmem_realloc(cft_list,
+			(cft_size + 1) * sizeof(struct cft_item),
+			cft_size  * sizeof(struct cft_item), KM_SLEEP);
+	cft_list[cft_size].table = cft;
+	cft_list[cft_size].size = size;
+	cft_list[cft_size].refcount = 1;
+	cft_size++;
+
+	mutex_unlock(&cft_lock);
+
+	return cft;
+}
+
+static void
+remove_cft(
+	const xfs_cft_t	*cft)
+{
+	int		i;
+
+	mutex_lock(&cft_lock);
+
+	for (i = 0; i < cft_size; i++) {
+		if (cft_list[i].table == cft) {
+			ASSERT(cft_list[i].refcount > 0);
+			cft_list[i].refcount--;
+			break;
+		}
+	}
+
+	mutex_unlock(&cft_lock);
+}
+
+
+int
+xfs_unicode_read_cft(
+	xfs_mount_t	*mp)
+{
+	int		error;
+	xfs_inode_t	*cftip;
+	int		size;
+	int		nfsb;
+	int             nmap;
+	xfs_bmbt_irec_t *mapp;
+	int		n;
+	int		byte_cnt;
+	xfs_buf_t	*bp;
+	char		*table;
+	xfs_dcft_t	*dcft;
+
+	if (mp->m_sb.sb_cftino == NULLFSINO || mp->m_sb.sb_cftino == 0)
+		return EINVAL;
+	error = xfs_iget(mp, NULL, mp->m_sb.sb_cftino, 0, 0, &cftip, 0);
+	if (error)
+		return error;
+	ASSERT(cftip != NULL);
+
+	size = cftip->i_d.di_size;
+	nfsb = cftip->i_d.di_nblocks;
+
+	table = vmalloc(size);
+	if (!table) {
+		xfs_iput(cftip, 0);
+		return ENOMEM;
+	}
+	dcft = (xfs_dcft_t *)table;
+
+	nmap = nfsb;
+	mapp = kmem_alloc(nfsb * sizeof(xfs_bmbt_irec_t), KM_SLEEP);
+
+	error = xfs_bmapi(NULL, cftip, 0, nfsb, 0, NULL, 0, mapp, &nmap,
+			NULL, NULL);
+	if (error)
+		goto out;
+
+	for (n = 0; n < nmap; n++) {
+		byte_cnt = XFS_FSB_TO_B(mp, mapp[n].br_blockcount);
+
+		error = xfs_read_buf(mp, mp->m_ddev_targp,
+				XFS_FSB_TO_DADDR(mp, mapp[n].br_startblock),
+				BTOBB(byte_cnt), 0, &bp);
+		if (error)
+			goto out;
+
+		if (size < byte_cnt)
+			byte_cnt = size;
+		size -= byte_cnt;
+		memcpy(table, XFS_BUF_PTR(bp), byte_cnt);
+		table += byte_cnt;
+		xfs_buf_relse(bp);
+	}
+
+	/* verify case table read off disk */
+	if (!uuid_equal(&dcft->uuid, &mp->m_sb.sb_uuid)) {
+		error = EINVAL;
+		goto out;
+	}
+
+	/* clear UUID for in-memory copy/compare */
+	memset(&dcft->uuid, 0, sizeof(dcft->uuid));
+
+	mp->m_cft = add_cft(dcft, cftip->i_d.di_size);
+	if (mp->m_cft == NULL)
+		error = ENOMEM;
+
+out:
+	xfs_iput(cftip, 0);
+	kmem_free(mapp, nfsb * sizeof(xfs_bmbt_irec_t));
+	vfree(dcft);
+
+	return error;
+}
+
+void
+xfs_unicode_free_cft(
+	const xfs_cft_t	*cft)
+{
+	if (cft)
+		remove_cft(cft);
+}
+
+void
+xfs_unicode_init(void)
+{
+	mutex_init(&cft_lock);
+}
+
+void
+xfs_unicode_uninit(void)
+{
+	int		i;
+
+	mutex_lock(&cft_lock);
+
+	for (i = 0; i < cft_size; i++) {
+		ASSERT(cft_list[i].refcount == 0);
+		vfree(cft_list[i].table);
+	}
+	kmem_free(cft_list, cft_size * sizeof(struct cft_item));
+	cft_size = 0;
+	cft_list = NULL;
+
+	mutex_unlock(&cft_lock);
+	mutex_destroy(&cft_lock);
+}
Index: kern_ci/fs/xfs/xfs_unicode.h
===================================================================
--- /dev/null
+++ kern_ci/fs/xfs/xfs_unicode.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2007-2008 Silicon Graphics, Inc.
+ * 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_UNICODE_H__
+#define	__XFS_UNICODE_H__
+
+#define	XFS_CFT_MAGIC		0x58434654	/* 'XCFT' */
+#define XFS_CFT_FLAG_TURKIC	0x00000001
+#define XFS_CFT_FLAG_MAX	0x00000001
+
+/*
+ * Case Fold Table - on disk version. Must match the incore version below.
+ */
+typedef struct xfs_dcft {
+	__be32			magic;		/* validity check */
+	__be32			flags;
+	uuid_t			uuid;		/* UUID of the filesystem */
+	__be32			crc;		/* for future support */
+	__be32			num_tables;	/* single, double, etc */
+	__be32			table_offset[1];
+} xfs_dcft_t;
+
+/*
+ * Case Fold Table - in core version. Must match the ondisk version above.
+ */
+typedef struct xfs_cft {
+	__uint32_t		magic;
+	__uint32_t		flags;
+	uuid_t			uuid;		/* UUID of the filesystem */
+	__uint32_t		crc;
+	__uint32_t		num_tables;	/* single, double, etc */
+	__uint32_t		table_offset[1];/* num_tables sized */
+	/* 16-bit array tables immediately follow */
+} xfs_cft_t;
+
+#define XFS_CFT_PTR(t,n)	(__uint16_t *)(((char *)(t)) + \
+					(t)->table_offset[n])
+#define XFS_DCFT_PTR(t,n)	(__be16 *)(((char *)(t)) + \
+					be32_to_cpu((t)->table_offset[n]))
+
+#ifdef CONFIG_XFS_UNICODE
+
+extern struct xfs_nameops xfs_unicode_nameops;
+extern struct xfs_nameops xfs_unicode_ci_nameops;
+
+void xfs_unicode_init(void);
+void xfs_unicode_uninit(void);
+
+int xfs_unicode_validate(const uchar_t *name, int namelen);
+
+int xfs_unicode_read_cft(struct xfs_mount *mp);
+void xfs_unicode_free_cft(const xfs_cft_t *cft);
+
+#else
+
+#define xfs_unicode_nameops		xfs_default_nameops
+#define xfs_unicode_ci_nameops		xfs_default_nameops
+
+#define xfs_unicode_init()
+#define xfs_unicode_uninit()
+#define xfs_unicode_validate(n,l)	0
+#define xfs_unicode_read_cft(mp)	(EOPNOTSUPP)
+#define xfs_unicode_free_cft(cft)
+
+#endif	/* CONFIG_XFS_UNICODE */
+
+#endif /* __XFS_UNICODE_H__ */
Index: kern_ci/fs/xfs/xfs_vfsops.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_vfsops.c
+++ kern_ci/fs/xfs/xfs_vfsops.c
@@ -56,6 +56,7 @@
 #include "xfs_vnodeops.h"
 #include "xfs_vfsops.h"
 #include "xfs_utils.h"
+#include "xfs_unicode.h"
 
 
 int __init
@@ -82,6 +83,7 @@ xfs_init(void)
 	xfs_acl_zone_init(xfs_acl_zone, "xfs_acl");
 	xfs_mru_cache_init();
 	xfs_filestream_init();
+	xfs_unicode_init();
 
 	/*
 	 * The size of the zone allocated buf log item is the maximum
@@ -157,6 +159,7 @@ xfs_cleanup(void)
 	xfs_filestream_uninit();
 	xfs_mru_cache_uninit();
 	xfs_acl_zone_destroy(xfs_acl_zone);
+	xfs_unicode_uninit();
 
 #ifdef XFS_DIR2_TRACE
 	ktrace_free(xfs_dir2_trace_buf);
@@ -399,6 +402,19 @@ xfs_finish_flags(
 			mp->m_qflags |= XFS_OQUOTA_ENFD;
 	}
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		if (ap->flags2 & XFSMNT2_CILOOKUP)
+			mp->m_flags |= XFS_MOUNT_CILOOKUP;
+	} else {
+		/*
+		 * Check for mount options which require a Unicode FS
+		 */
+		if (ap->flags2 & XFSMNT2_CILOOKUP) {
+			cmn_err(CE_WARN,
+	"XFS: can't do case-insensitive mount on non-utf8 filesystem");
+			return XFS_ERROR(EINVAL);
+		}
+	}
 	return 0;
 }
 
Index: kern_ci/fs/xfs/xfs_vnodeops.c
===================================================================
--- kern_ci.orig/fs/xfs/xfs_vnodeops.c
+++ kern_ci/fs/xfs/xfs_vnodeops.c
@@ -52,6 +52,7 @@
 #include "xfs_log_priv.h"
 #include "xfs_filestream.h"
 #include "xfs_vnodeops.h"
+#include "xfs_unicode.h"
 
 int
 xfs_open(
@@ -1777,6 +1778,12 @@ xfs_lookup(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return XFS_ERROR(EIO);
 
+	if (xfs_sb_version_hasunicode(&dp->i_mount->m_sb)) {
+		error = xfs_unicode_validate(d_name->name, d_name->len);
+		if (error)
+			return error;
+	}
+
 	name.name = (uchar_t *)d_name->name;
 	name.len = d_name->len;
 	rname.name = NULL;
@@ -1822,8 +1829,17 @@ xfs_create(
 	ASSERT(!*ipp);
 	xfs_itrace_entry(dp);
 
+	if (XFS_FORCED_SHUTDOWN(mp))
+		return XFS_ERROR(EIO);
+
 	namelen = VNAMELEN(dentry);
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		error = xfs_unicode_validate(name, namelen);
+		if (error)
+			return error;
+	}
+
 	if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) {
 		error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
 				dp, DM_RIGHT_NULL, NULL,
@@ -1835,9 +1851,6 @@ xfs_create(
 		dm_event_sent = 1;
 	}
 
-	if (XFS_FORCED_SHUTDOWN(mp))
-		return XFS_ERROR(EIO);
-
 	/* Return through std_return after this point. */
 
 	udqp = gdqp = NULL;
@@ -2282,7 +2295,7 @@ xfs_remove(
 	xfs_inode_t             *ip = VNAME_TO_INODE(dentry);
 	int			namelen = VNAMELEN(dentry);
 	xfs_trans_t             *tp = NULL;
-	int                     error = 0;
+	int                     error;
 	xfs_bmap_free_t         free_list;
 	xfs_fsblock_t           first_block;
 	int			cancel_flags;
@@ -2295,6 +2308,12 @@ xfs_remove(
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return XFS_ERROR(EIO);
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		error = xfs_unicode_validate(name, namelen);
+		if (error)
+			return error;
+	}
+
 	if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) {
 		error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dp,
 					DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
@@ -2504,6 +2523,12 @@ xfs_link(
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return XFS_ERROR(EIO);
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		error = xfs_unicode_validate(target_name, target_namelen);
+		if (error)
+			return error;
+	}
+
 	if (DM_EVENT_ENABLED(tdp, DM_EVENT_LINK)) {
 		error = XFS_SEND_NAMESP(mp, DM_EVENT_LINK,
 					tdp, DM_RIGHT_NULL,
@@ -2661,6 +2686,12 @@ xfs_mkdir(
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return XFS_ERROR(EIO);
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		error = xfs_unicode_validate(dir_name, dir_namelen);
+		if (error)
+			return error;
+	}
+
 	tp = NULL;
 
 	if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) {
@@ -2869,6 +2900,12 @@ xfs_rmdir(
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return XFS_ERROR(EIO);
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		error = xfs_unicode_validate(name, namelen);
+		if (error)
+			return error;
+	}
+
 	if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) {
 		error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE,
 					dp, DM_RIGHT_NULL,
@@ -3097,7 +3134,6 @@ xfs_symlink(
 	int			link_namelen;
 
 	*ipp = NULL;
-	error = 0;
 	ip = NULL;
 	tp = NULL;
 
@@ -3108,6 +3144,12 @@ xfs_symlink(
 
 	link_namelen = VNAMELEN(dentry);
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		error = xfs_unicode_validate(link_name, link_namelen);
+		if (error)
+			return error;
+	}
+
 	/*
 	 * Check component lengths of the target path name.
 	 */

-- 

  parent reply	other threads:[~2008-04-02  6:27 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-04-02  6:25 [PATCH 0/7] XFS: case-insensitive lookup and Unicode support Barry Naujok
2008-04-02  6:25 ` [PATCH 1/7] XFS: Name operation vector for hash and compare Barry Naujok
2008-04-03  0:22   ` Josef 'Jeff' Sipek
2008-04-03  4:50     ` Barry Naujok
2008-04-03  1:29   ` David Chinner
2008-04-03  1:45     ` Barry Naujok
2008-04-03 22:51     ` Christoph Hellwig
2008-04-02  6:25 ` [PATCH 2/7] XFS: ASCII case-insensitive support Barry Naujok
2008-04-03  0:35   ` Josef 'Jeff' Sipek
2008-04-03  1:53   ` David Chinner
2008-04-03 17:09     ` Christoph Hellwig
2008-04-03 22:55   ` Christoph Hellwig
2008-04-03 23:01     ` Nathan Scott
2008-04-02  6:25 ` [PATCH 3/7] XFS: Refactor node format directory lookup/addname Barry Naujok
2008-04-03  1:51   ` Josef 'Jeff' Sipek
2008-04-03  4:04     ` Barry Naujok
2008-04-03  4:10       ` Barry Naujok
2008-04-03  4:33   ` David Chinner
2008-04-02  6:25 ` [PATCH 4/7] XFS: Return case-insensitive match for dentry cache Barry Naujok
2008-04-03  2:34   ` Josef 'Jeff' Sipek
2008-04-03  5:22   ` David Chinner
2008-04-03  5:41     ` Stephen Rothwell
2008-04-03 14:56       ` Christoph Hellwig
2008-04-03 23:06   ` Christoph Hellwig
2008-04-02  6:25 ` Barry Naujok [this message]
2008-04-03  8:31   ` [PATCH 5/7] XFS: Unicode case-insensitive lookup implementation David Chinner
2008-04-17  5:38     ` Barry Naujok
2008-04-17  8:49       ` David Chinner
2008-04-03 17:14   ` Christoph Hellwig
2008-04-03 17:24     ` Jeremy Allison
2008-04-03 18:09       ` Josef 'Jeff' Sipek
2008-04-03 18:11       ` Eric Sandeen
2008-04-03 18:22         ` Jeremy Allison
2008-04-04  0:00         ` Mark Goodwin
2008-04-03 18:43       ` Christoph Hellwig
2008-04-03 18:47         ` Jeremy Allison
2008-04-03 18:55           ` Christoph Hellwig
2008-04-03 18:57             ` Christoph Hellwig
2008-04-03 22:34               ` Jeremy Allison
2008-04-03 22:20     ` David Chinner
2008-04-03 22:31       ` Christoph Hellwig
2008-04-03 23:00       ` Jamie Lokier
2008-04-02  6:25 ` [PATCH 6/7] XFS: Native Language Support for Unicode in XFS Barry Naujok
2008-04-02  6:25   ` Barry Naujok
2008-04-04  0:05   ` David Chinner
2008-04-04  0:05     ` David Chinner
2008-04-02  6:25 ` [PATCH 7/7] XFS: NLS config option Barry Naujok
2008-04-03  1:26   ` Josef 'Jeff' Sipek
2008-04-03  1:38     ` Barry Naujok
2008-04-08 11:45 ` [PATCH 0/7] XFS: case-insensitive lookup and Unicode support Christoph Hellwig
2008-04-09  1:53   ` Barry Naujok

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080402062709.011126702@chook.melbourne.sgi.com \
    --to=bnaujok@sgi.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=xfs@oss.sgi.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.