public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
* [REVIEW 2/2] Case insensitive support for XFS - user-space
@ 2008-01-18  4:43 Barry Naujok
  2008-01-18 21:23 ` Eric Sandeen
  0 siblings, 1 reply; 7+ messages in thread
From: Barry Naujok @ 2008-01-18  4:43 UTC (permalink / raw)
  To: xfs@oss.sgi.com; +Cc: xfs-dev

[-- Attachment #1: Type: text/plain, Size: 1779 bytes --]

This patch relies on the dinode.c refactoring patch posted recently.
I have attached the latest version (with fixes pointed out by Chandan).


  db/Makefile             |    2
  db/cft.c                |  135 ++++++++
  db/cft.h                |   23 +
  db/check.c              |  236 ++++++++++++++
  db/command.c            |    2
  db/field.c              |    3
  db/field.h              |    1
  db/inode.c              |    2
  db/metadump.c           |    3
  db/sb.c                 |    5
  db/type.c               |    2
  db/type.h               |    2
  include/casefoldtable.h |   29 +
  include/libxfs.h        |   12
  include/xfs_attr_leaf.h |    8
  include/xfs_da_btree.h  |   34 ++
  include/xfs_dir2.h      |    7
  include/xfs_sb.h        |   33 +-
  include/xfs_unicode.h   |   69 ++++
  libxfs/Makefile         |    6
  libxfs/casefoldtable.c  |  760  
++++++++++++++++++++++++++++++++++++++++++++++++
  libxfs/init.c           |   10
  libxfs/utf8.c           |   85 +++++
  libxfs/xfs.h            |   20 +
  libxfs/xfs_attr.c       |   35 +-
  libxfs/xfs_attr_leaf.c  |   11
  libxfs/xfs_da_btree.c   |   86 +++++
  libxfs/xfs_dir2.c       |  220 ++++++++-----
  libxfs/xfs_dir2_block.c |    5
  libxfs/xfs_dir2_data.c  |    3
  libxfs/xfs_mount.c      |    2
  libxfs/xfs_unicode.c    |  405 +++++++++++++++++++++++++
  mdrestore/Makefile      |    2
  mkfs/proto.c            |   24 +
  mkfs/xfs_mkfs.c         |  101 +++---
  mkfs/xfs_mkfs.h         |   13
  repair/agheader.c       |   12
  repair/dino_chunks.c    |   15
  repair/dinode.c         |  112 +++++++
  repair/dir2.c           |    3
  repair/incore.h         |    1
  repair/phase2.c         |   19 +
  repair/phase6.c         |  257 ++++++++++------
  repair/xfs_repair.c     |   20 +

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: dinode.patch --]
[-- Type: text/x-patch; name=dinode.patch, Size: 65567 bytes --]


===========================================================================
xfsprogs/repair/dino_chunks.c
===========================================================================

Index: ci/xfsprogs/repair/dino_chunks.c
===================================================================
--- ci.orig/xfsprogs/repair/dino_chunks.c	2007-11-16 14:45:56.000000000 +1100
+++ ci/xfsprogs/repair/dino_chunks.c	2008-01-18 14:50:42.000000000 +1100
@@ -593,7 +593,6 @@
 	xfs_agino_t		agino;
 	xfs_agblock_t		agbno;
 	int			dirty = 0;
-	int			cleared = 0;
 	int			isa_dir = 0;
 	int			blks_per_cluster;
 	int			cluster_count;
@@ -777,8 +776,7 @@
 
 		status = process_dinode(mp, dino, agno, agino,
 				is_inode_free(ino_rec, irec_offset),
-				&ino_dirty, &cleared, &is_used,
-				ino_discovery, check_dups,
+				&ino_dirty, &is_used,ino_discovery, check_dups,
 				extra_attr_check, &isa_dir, &parent);
 
 		ASSERT(is_used != 3);
Index: ci/xfsprogs/repair/dinode.c
===================================================================
--- ci.orig/xfsprogs/repair/dinode.c	2007-11-16 14:45:56.000000000 +1100
+++ ci/xfsprogs/repair/dinode.c	2008-01-18 14:57:36.000000000 +1100
@@ -58,9 +58,6 @@
 	case XFS_DINODE_FMT_LOCAL:
 		offset += INT_GET(dinoc->di_size, ARCH_CONVERT);
 		break;
-	case XFS_DINODE_FMT_UUID:
-		offset += sizeof(uuid_t);
-		break;
 	case XFS_DINODE_FMT_EXTENTS:
 		offset += INT_GET(dinoc->di_nextents, ARCH_CONVERT) * sizeof(xfs_bmbt_rec_32_t);
 		break;
@@ -1563,8 +1560,11 @@
  * bogus
  */
 int
-process_symlink(xfs_mount_t *mp, xfs_ino_t lino, xfs_dinode_t *dino,
-		blkmap_t *blkmap)
+process_symlink(
+	xfs_mount_t	*mp,
+	xfs_ino_t	lino,
+	xfs_dinode_t	*dino,
+	blkmap_t 	*blkmap)
 {
 	xfs_dfsbno_t		fsbno;
 	xfs_dinode_core_t	*dinoc = &dino->di_core;
@@ -1673,8 +1673,7 @@
  * called to process the set of misc inode special inode types
  * that have no associated data storage (fifos, pipes, devices, etc.).
  */
-/* ARGSUSED */
-int
+static int
 process_misc_ino_types(xfs_mount_t	*mp,
 			xfs_dinode_t	*dino,
 			xfs_ino_t	lino,
@@ -1693,27 +1692,27 @@
 	/*
 	 * must also have a zero size
 	 */
-	if (INT_GET(dino->di_core.di_size, ARCH_CONVERT) != 0)  {
+	if (dino->di_core.di_size)  {
 		switch (type)  {
 		case XR_INO_CHRDEV:
 			do_warn(_("size of character device inode %llu != 0 "
 				  "(%lld bytes)\n"), lino,
-				INT_GET(dino->di_core.di_size, ARCH_CONVERT));
+				be64_to_cpu(dino->di_core.di_size));
 			break;
 		case XR_INO_BLKDEV:
 			do_warn(_("size of block device inode %llu != 0 "
 				  "(%lld bytes)\n"), lino,
-				INT_GET(dino->di_core.di_size, ARCH_CONVERT));
+				be64_to_cpu(dino->di_core.di_size));
 			break;
 		case XR_INO_SOCK:
 			do_warn(_("size of socket inode %llu != 0 "
 				  "(%lld bytes)\n"), lino,
-				INT_GET(dino->di_core.di_size, ARCH_CONVERT));
+				be64_to_cpu(dino->di_core.di_size));
 			break;
 		case XR_INO_FIFO:
 			do_warn(_("size of fifo inode %llu != 0 "
 				  "(%lld bytes)\n"), lino,
-				INT_GET(dino->di_core.di_size, ARCH_CONVERT));
+				be64_to_cpu(dino->di_core.di_size));
 			break;
 		default:
 			do_warn(_("Internal error - process_misc_ino_types, "
@@ -1769,712 +1768,395 @@
 	return (0);
 }
 
-/*
- * returns 0 if the inode is ok, 1 if the inode is corrupt
- * check_dups can be set to 1 *only* when called by the
- * first pass of the duplicate block checking of phase 4.
- * *dirty is set > 0 if the dinode has been altered and
- * needs to be written out.
- *
- * for detailed, info, look at process_dinode() comments.
- */
-/* ARGSUSED */
-int
-process_dinode_int(xfs_mount_t *mp,
-		xfs_dinode_t *dino,
-		xfs_agnumber_t agno,
-		xfs_agino_t ino,
-		int was_free,		/* 1 if inode is currently free */
-		int *dirty,		/* out == > 0 if inode is now dirty */
-		int *cleared,		/* out == 1 if inode was cleared */
-		int *used,		/* out == 1 if inode is in use */
-		int verify_mode,	/* 1 == verify but don't modify inode */
-		int uncertain,		/* 1 == inode is uncertain */
-		int ino_discovery,	/* 1 == check dirs for unknown inodes */
-		int check_dups,		/* 1 == check if inode claims
-					 * duplicate blocks		*/
-		int extra_attr_check, /* 1 == do attribute format and value checks */
-		int *isa_dir,		/* out == 1 if inode is a directory */
-		xfs_ino_t *parent)	/* out -- parent if ino is a dir */
+static inline int
+dinode_fmt(
+	xfs_dinode_core_t *dinoc)
 {
-	xfs_drfsbno_t		totblocks = 0;
-	xfs_drfsbno_t		atotblocks = 0;
-	xfs_dinode_core_t	*dinoc;
-	char			*rstring;
-	int			type;
-	int			rtype;
-	int			do_rt;
-	int			err;
-	int			retval = 0;
-	__uint64_t		nextents;
-	__uint64_t		anextents;
-	xfs_ino_t		lino;
-	const int		is_free = 0;
-	const int		is_used = 1;
-	int			repair = 0;
-	blkmap_t		*ablkmap = NULL;
-	blkmap_t		*dblkmap = NULL;
-	static char		okfmts[] = {
-		0,				/* free inode */
-		1 << XFS_DINODE_FMT_DEV,	/* FIFO */
-		1 << XFS_DINODE_FMT_DEV,	/* CHR */
-		0,				/* type 3 unused */
-		(1 << XFS_DINODE_FMT_LOCAL) |
-		(1 << XFS_DINODE_FMT_EXTENTS) |
-		(1 << XFS_DINODE_FMT_BTREE),	/* DIR */
-		0,				/* type 5 unused */
-		1 << XFS_DINODE_FMT_DEV,	/* BLK */
-		0,				/* type 7 unused */
-		(1 << XFS_DINODE_FMT_EXTENTS) |
-		(1 << XFS_DINODE_FMT_BTREE),	/* REG */
-		0,				/* type 9 unused */
-		(1 << XFS_DINODE_FMT_LOCAL) |
-		(1 << XFS_DINODE_FMT_EXTENTS),	/* LNK */
-		0,				/* type 11 unused */
-		1 << XFS_DINODE_FMT_DEV,	/* SOCK */
-		0,				/* type 13 unused */
-		1 << XFS_DINODE_FMT_UUID,	/* MNT */
-		0				/* type 15 unused */
-	};
-
-	retval = 0;
-	totblocks = atotblocks = 0;
-	*dirty = *isa_dir = *cleared = 0;
-	*used = is_used;
-	type = rtype = XR_INO_UNKNOWN;
-	rstring = NULL;
-	do_rt = 0;
+	return be16_to_cpu(dinoc->di_mode) & S_IFMT;
+}
 
-	dinoc = &dino->di_core;
-	lino = XFS_AGINO_TO_INO(mp, agno, ino);
+static inline void
+change_dinode_fmt(
+	xfs_dinode_core_t *dinoc,
+	int		new_fmt)
+{
+	int		mode = be16_to_cpu(dinoc->di_mode);
 
-	/*
-	 * if in verify mode, don't modify the inode.
-	 *
-	 * if correcting, reset stuff that has known values
-	 *
-	 * if in uncertain mode, be silent on errors since we're
-	 * trying to find out if these are inodes as opposed
-	 * to assuming that they are.  Just return the appropriate
-	 * return code in that case.
-	 */
+	ASSERT((new_fmt & ~S_IFMT) == 0);
 
-	if (INT_GET(dinoc->di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC)  {
-		retval++;
-		if (!verify_mode)  {
-			do_warn(_("bad magic number 0x%x on inode %llu, "),
-				INT_GET(dinoc->di_magic, ARCH_CONVERT), lino);
+	mode &= ~S_IFMT;
+	mode |= new_fmt;
+	dinoc->di_mode = cpu_to_be16(mode);
+}
+
+static int
+check_dinode_mode_format(
+	xfs_dinode_core_t *dinoc)
+{
+	if ((uchar_t)dinoc->di_format >= XFS_DINODE_FMT_UUID)
+		return -1;	/* FMT_UUID is not used */
+
+	switch (dinode_fmt(dinoc)) {
+	case S_IFIFO:
+	case S_IFCHR:
+	case S_IFBLK:
+	case S_IFSOCK:
+		return (dinoc->di_format != XFS_DINODE_FMT_DEV) ? -1 : 0;
+
+	case S_IFDIR:
+		return (dinoc->di_format < XFS_DINODE_FMT_LOCAL ||
+			dinoc->di_format > XFS_DINODE_FMT_BTREE) ? -1 : 0;
+
+	case S_IFREG:
+		return (dinoc->di_format < XFS_DINODE_FMT_EXTENTS ||
+			dinoc->di_format > XFS_DINODE_FMT_BTREE) ? -1 : 0;
+
+	case S_IFLNK:
+		return (dinoc->di_format < XFS_DINODE_FMT_LOCAL ||
+			dinoc->di_format > XFS_DINODE_FMT_EXTENTS) ? -1 : 0;
+
+	default: ;
+	}
+	return 0;	/* invalid modes are checked elsewhere */
+}
+
+/*
+ * If inode is a superblock inode, does type check to make sure is it valid.
+ * Returns 0 if it's valid, non-zero if it needs to be cleared.
+ */
+
+static int
+process_check_sb_inodes(
+	xfs_mount_t	*mp,
+	xfs_dinode_core_t *dinoc,
+	xfs_ino_t	lino,
+	int		*type,
+	int		*dirty)
+{
+	if (lino == mp->m_sb.sb_rootino) {
+	 	if (*type != XR_INO_DIR)  {
+			do_warn(_("root inode %llu has bad type 0x%x\n"),
+				lino, dinode_fmt(dinoc));
+			*type = XR_INO_DIR;
 			if (!no_modify)  {
-				do_warn(_("resetting magic number\n"));
+				do_warn(_("resetting to directory\n"));
+				change_dinode_fmt(dinoc, S_IFDIR);
 				*dirty = 1;
-				INT_SET(dinoc->di_magic, ARCH_CONVERT,
-					XFS_DINODE_MAGIC);
-			} else  {
-				do_warn(_("would reset magic number\n"));
-			}
-		} else if (!uncertain) {
-			do_warn(_("bad magic number 0x%x on inode %llu\n"),
-				INT_GET(dinoc->di_magic, ARCH_CONVERT), lino);
+			} else
+				do_warn(_("would reset to directory\n"));
 		}
+		return 0;
 	}
-
-	if (!XFS_DINODE_GOOD_VERSION(dinoc->di_version) ||
-	    (!fs_inode_nlink && dinoc->di_version > XFS_DINODE_VERSION_1))  {
-		retval++;
-		if (!verify_mode)  {
-			do_warn(_("bad version number 0x%x on inode %llu, "),
-				dinoc->di_version, lino);
+	if (lino == mp->m_sb.sb_uquotino)  {
+		if (*type != XR_INO_DATA)  {
+			do_warn(_("user quota inode %llu has bad type 0x%x\n"),
+				lino, dinode_fmt(dinoc));
+			mp->m_sb.sb_uquotino = NULLFSINO;
+			return 1;
+		}
+		return 0;
+	}
+	if (lino == mp->m_sb.sb_gquotino)  {
+		if (*type != XR_INO_DATA)  {
+			do_warn(_("group quota inode %llu has bad type 0x%x\n"),
+				lino, dinode_fmt(dinoc));
+			mp->m_sb.sb_gquotino = NULLFSINO;
+			return 1;
+		}
+		return 0;
+	}
+	if (lino == mp->m_sb.sb_rsumino) {
+		if (*type != XR_INO_RTSUM) {
+			do_warn(_("realtime summary inode %llu has bad type 0x%x, "),
+				lino, dinode_fmt(dinoc));
 			if (!no_modify)  {
-				do_warn(_("resetting version number\n"));
+				do_warn(_("resetting to regular file\n"));
+				change_dinode_fmt(dinoc, S_IFREG);
 				*dirty = 1;
-				dinoc->di_version = (fs_inode_nlink) ?
-					XFS_DINODE_VERSION_2 :
-					XFS_DINODE_VERSION_1;
 			} else  {
-				do_warn(_("would reset version number\n"));
+				do_warn(_("would reset to regular file\n"));
 			}
-		} else  if (!uncertain) {
-			do_warn(_("bad version number 0x%x on inode %llu\n"),
-				dinoc->di_version, lino);
 		}
+		if (mp->m_sb.sb_rblocks == 0 && dinoc->di_nextents != 0)  {
+			do_warn(_("bad # of extents (%u) for realtime summary inode %llu\n"),
+				be32_to_cpu(dinoc->di_nextents), lino);
+			return 1;
+		}
+		return 0;
 	}
-
-	/*
-	 * blow out of here if the inode size is < 0
-	 */
-	if (INT_GET(dinoc->di_size, ARCH_CONVERT) < 0)  {
-		retval++;
-		if (!verify_mode)  {
-			do_warn(_("bad (negative) size %lld on inode %llu\n"),
-				INT_GET(dinoc->di_size, ARCH_CONVERT), lino);
+	if (lino == mp->m_sb.sb_rbmino) {
+		if (*type != XR_INO_RTBITMAP) {
+			do_warn(_("realtime bitmap inode %llu has bad type 0x%x, "),
+				lino, dinode_fmt(dinoc));
 			if (!no_modify)  {
-				*dirty += clear_dinode(mp, dino, lino);
-				*cleared = 1;
-			} else  {
+				do_warn(_("resetting to regular file\n"));
+				change_dinode_fmt(dinoc, S_IFREG);
 				*dirty = 1;
-				*cleared = 1;
+			} else  {
+				do_warn(_("would reset to regular file\n"));
 			}
-			*used = is_free;
-		} else if (!uncertain)  {
-			do_warn(_("bad (negative) size %lld on inode %llu\n"),
-				INT_GET(dinoc->di_size, ARCH_CONVERT), lino);
 		}
-
-		return(1);
-	}
-
-	/*
-	 * was_free value is not meaningful if we're in verify mode
-	 */
-	if (!verify_mode && INT_GET(dinoc->di_mode, ARCH_CONVERT) == 0 && was_free == 1)  {
-		/*
-		 * easy case, inode free -- inode and map agree, clear
-		 * it just in case to ensure that format, etc. are
-		 * set correctly
-		 */
-		if (!no_modify)  {
-			err =  clear_dinode(mp, dino, lino);
-			if (err)  {
-				*dirty = 1;
-				*cleared = 1;
-			}
+		if (mp->m_sb.sb_rblocks == 0 && dinoc->di_nextents != 0)  {
+			do_warn(_("bad # of extents (%u) for realtime bitmap inode %llu\n"),
+				be32_to_cpu(dinoc->di_nextents), lino);
+			return 1;
 		}
-		*used = is_free;
-		return(0);
-	} else if (!verify_mode && INT_GET(dinoc->di_mode, ARCH_CONVERT) == 0 && was_free == 0)  {
-		/*
-		 * the inode looks free but the map says it's in use.
-		 * clear the inode just to be safe and mark the inode
-		 * free.
-		 */
-		do_warn(_("imap claims a free inode %llu is in use, "), lino);
+		return 0;
+	}
+	return 0;
+}
 
-		if (!no_modify)  {
-			do_warn(_("correcting imap and clearing inode\n"));
+/*
+ * general size/consistency checks:
+ *
+ * if the size <= size of the data fork, directories  must be
+ * local inodes unlike regular files which would be extent inodes.
+ * all the other mentioned types have to have a zero size value.
+ *
+ * if the size and format don't match, get out now rather than
+ * risk trying to process a non-existent extents or btree
+ * type data fork.
+ */
+static int
+process_check_inode_sizes(
+	xfs_mount_t	*mp,
+	xfs_dinode_t	*dino,
+	xfs_ino_t	lino,
+	int		type)
+{
+	xfs_dinode_core_t *dinoc = &dino->di_core;
+	xfs_fsize_t	size = be64_to_cpu(dinoc->di_size);
 
-			err =  clear_dinode(mp, dino, lino);
-			if (err)  {
-				retval++;
-				*dirty = 1;
-				*cleared = 1;
-			}
-		} else  {
-			do_warn(_("would correct imap and clear inode\n"));
+	switch (type)  {
 
-			*dirty = 1;
-			*cleared = 1;
+	case XR_INO_DIR:
+		if (size <= XFS_DFORK_DSIZE(dino, mp) &&
+				dinoc->di_format != XFS_DINODE_FMT_LOCAL) {
+			do_warn(_("mismatch between format (%d) and size "
+				"(%lld) in directory ino %llu\n"),
+				dinoc->di_format, size, lino);
+			return 1;
 		}
+		break;
 
-		*used = is_free;
-
-		return(retval > 0 ? 1 : 0);
-	}
-
-	/*
-	 * because of the lack of any write ordering guarantee, it's
-	 * possible that the core got updated but the forks didn't.
-	 * so rather than be ambitious (and probably incorrect),
-	 * if there's an inconsistency, we get conservative and
-	 * just pitch the file.  blow off checking formats of
-	 * free inodes since technically any format is legal
-	 * as we reset the inode when we re-use it.
-	 */
-	if (INT_GET(dinoc->di_mode, ARCH_CONVERT) != 0 &&
-		((((INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT) >> 12) > 15) ||
-		(uchar_t) dinoc->di_format > XFS_DINODE_FMT_UUID ||
-			(!(okfmts[(INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT) >> 12] &
-			  (1 << dinoc->di_format))))) {
-		/* bad inode format */
-		retval++;
-		if (!uncertain)
-			do_warn(_("bad inode format in inode %llu\n"), lino);
-		if (!verify_mode)  {
-			if (!no_modify)  {
-				*dirty += clear_dinode(mp, dino, lino);
-				ASSERT(*dirty > 0);
-			}
+	case XR_INO_SYMLINK:
+		if (process_symlink_extlist(mp, lino, dino))  {
+			do_warn(_("bad data fork in symlink %llu\n"), lino);
+			return 1;
 		}
-		*cleared = 1;
-		*used = is_free;
-
-		return(retval > 0 ? 1 : 0);
-	}
-
-	if (verify_mode)
-		return(retval > 0 ? 1 : 0);
-
-	/*
-	 * clear the next unlinked field if necessary on a good
-	 * inode only during phase 4 -- when checking for inodes
-	 * referencing duplicate blocks.  then it's safe because
-	 * we've done the inode discovery and have found all the inodes
-	 * we're going to find.  check_dups is set to 1 only during
-	 * phase 4.  Ugly.
-	 */
-	if (check_dups && !no_modify)
-		*dirty += clear_dinode_unlinked(mp, dino);
-
-	/* set type and map type info */
+		break;
 
-	switch (INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT) {
-	case S_IFDIR:
-		type = XR_INO_DIR;
-		*isa_dir = 1;
+	case XR_INO_CHRDEV:	/* fall through to FIFO case ... */
+	case XR_INO_BLKDEV:	/* fall through to FIFO case ... */
+	case XR_INO_SOCK:	/* fall through to FIFO case ... */
+	case XR_INO_MOUNTPOINT:	/* fall through to FIFO case ... */
+	case XR_INO_FIFO:
+		if (process_misc_ino_types(mp, dino, lino, type))
+			return 1;
 		break;
-	case S_IFREG:
-		if (INT_GET(dinoc->di_flags, ARCH_CONVERT) & XFS_DIFLAG_REALTIME)
-			type = XR_INO_RTDATA;
-		else if (lino == mp->m_sb.sb_rbmino)
-			type = XR_INO_RTBITMAP;
-		else if (lino == mp->m_sb.sb_rsumino)
-			type = XR_INO_RTSUM;
-		else
-			type = XR_INO_DATA;
+
+	case XR_INO_RTDATA:
+		/*
+		 * if we have no realtime blocks, any inode claiming
+		 * to be a real-time file is bogus
+		 */
+		if (mp->m_sb.sb_rblocks == 0)  {
+			do_warn(_("found inode %llu claiming to be a "
+				"real-time file\n"), lino);
+			return 1;
+		}
 		break;
-	case S_IFLNK:
-		type = XR_INO_SYMLINK;
+
+	case XR_INO_RTBITMAP:
+		if (size != (__int64_t)mp->m_sb.sb_rbmblocks *
+					mp->m_sb.sb_blocksize) {
+			do_warn(_("realtime bitmap inode %llu has bad size "
+				"%lld (should be %lld)\n"),
+				lino, size, (__int64_t) mp->m_sb.sb_rbmblocks *
+					mp->m_sb.sb_blocksize);
+			return 1;
+		}
 		break;
-	case S_IFCHR:
-		type = XR_INO_CHRDEV;
+
+	case XR_INO_RTSUM:
+		if (size != mp->m_rsumsize)  {
+			do_warn(_("realtime summary inode %llu has bad size "
+				"%lld (should be %d)\n"),
+				lino, size, mp->m_rsumsize);
+			return 1;
+		}
 		break;
-	case S_IFBLK:
-		type = XR_INO_BLKDEV;
+
+	default:
 		break;
-	case S_IFSOCK:
-		type = XR_INO_SOCK;
+	}
+	return 0;
+}
+
+/*
+ * check for illegal values of forkoff
+ */
+static int
+process_check_inode_forkoff(
+	xfs_mount_t	*mp,
+	xfs_dinode_core_t *dinoc,
+	xfs_ino_t	lino)
+{
+	if (dinoc->di_forkoff == 0)
+		return 0;
+
+	switch (dinoc->di_format)  {
+	case XFS_DINODE_FMT_DEV:
+		if (dinoc->di_forkoff != (roundup(sizeof(xfs_dev_t), 8) >> 3)) {
+			do_warn(_("bad attr fork offset %d in dev inode %llu, "
+				"should be %d\n"), dinoc->di_forkoff, lino,
+				(int)(roundup(sizeof(xfs_dev_t), 8) >> 3));
+			return 1;
+		}
 		break;
-	case S_IFIFO:
-		type = XR_INO_FIFO;
+	case XFS_DINODE_FMT_LOCAL:	/* fall through ... */
+	case XFS_DINODE_FMT_EXTENTS:	/* fall through ... */
+	case XFS_DINODE_FMT_BTREE:
+		if (dinoc->di_forkoff >= (XFS_LITINO(mp) >> 3)) {
+			do_warn(_("bad attr fork offset %d in inode %llu, "
+				"max=%d\n"), dinoc->di_forkoff, lino,
+				XFS_LITINO(mp) >> 3);
+			return 1;
+		}
 		break;
 	default:
-		retval++;
-		if (!verify_mode)  {
-			do_warn(_("bad inode type %#o inode %llu\n"),
-				(int) (INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT), lino);
-			if (!no_modify)
-				*dirty += clear_dinode(mp, dino, lino);
-			else
-				*dirty = 1;
-			*cleared = 1;
-			*used = is_free;
-		} else if (!uncertain)  {
-			do_warn(_("bad inode type %#o inode %llu\n"),
-				(int) (INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT), lino);
-		}
-		return 1;
+		do_error(_("unexpected inode format %d\n"), dinoc->di_format);
+		break;
 	}
+	return 0;
+}
 
-	/*
-	 * type checks for root, realtime inodes, and quota inodes
-	 */
-	if (lino == mp->m_sb.sb_rootino && type != XR_INO_DIR)  {
-		do_warn(_("bad inode type for root inode %llu, "), lino);
-		type = XR_INO_DIR;
-
+/*
+ * Updates the inodes block and extent counts if they are wrong
+ */
+static int
+process_inode_blocks_and_extents(
+	xfs_dinode_core_t *dinoc,
+	xfs_drfsbno_t	nblocks,
+	__uint64_t	nextents,
+	__uint64_t	anextents,
+	xfs_ino_t	lino,
+	int		*dirty)
+{
+	if (nblocks != be64_to_cpu(dinoc->di_nblocks))  {
 		if (!no_modify)  {
-			do_warn(_("resetting to directory\n"));
-			INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT,
-			  &= ~(INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT));
-			INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT,
-			  |= INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFDIR);
+			do_warn(_("correcting nblocks for inode %llu, "
+				"was %llu - counted %llu\n"), lino,
+				be64_to_cpu(dinoc->di_nblocks), nblocks);
+			dinoc->di_nblocks = cpu_to_be64(nblocks);
+			*dirty = 1;
 		} else  {
-			do_warn(_("would reset to directory\n"));
+			do_warn(_("bad nblocks %llu for inode %llu, "
+				"would reset to %llu\n"),
+				be64_to_cpu(dinoc->di_nblocks), lino, nblocks);
 		}
-	} else if (lino == mp->m_sb.sb_rsumino)  {
-		do_rt = 1;
-		rstring = _("summary");
-		rtype = XR_INO_RTSUM;
-	} else if (lino == mp->m_sb.sb_rbmino)  {
-		do_rt = 1;
-		rstring = _("bitmap");
-		rtype = XR_INO_RTBITMAP;
-	} else if (lino == mp->m_sb.sb_uquotino)  {
-		if (type != XR_INO_DATA)  {
-			do_warn(_("user quota inode has bad type 0x%x\n"),
-				INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT);
+	}
 
-			if (!no_modify)  {
-				*dirty += clear_dinode(mp, dino, lino);
-				ASSERT(*dirty > 0);
-			}
-
-			*cleared = 1;
-			*used = is_free;
-			*isa_dir = 0;
-
-			mp->m_sb.sb_uquotino = NULLFSINO;
-
-			return(1);
-		}
-	} else if (lino == mp->m_sb.sb_gquotino)  {
-		if (type != XR_INO_DATA)  {
-			do_warn(_("group quota inode has bad type 0x%x\n"),
-				INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT);
-
-			if (!no_modify)  {
-				*dirty += clear_dinode(mp, dino, lino);
-				ASSERT(*dirty > 0);
-			}
-
-			*cleared = 1;
-			*used = is_free;
-			*isa_dir = 0;
-
-			mp->m_sb.sb_gquotino = NULLFSINO;
-
-			return(1);
-		}
+	if (nextents > MAXEXTNUM)  {
+		do_warn(_("too many data fork extents (%llu) in inode %llu\n"),
+			nextents, lino);
+		return 1;
 	}
-
-	if (do_rt && type != rtype)  {
-		type = XR_INO_DATA;
-
-		do_warn(_("bad inode type for realtime %s inode %llu, "),
-			rstring, lino);
-
+	if (nextents != be32_to_cpu(dinoc->di_nextents))  {
 		if (!no_modify)  {
-			do_warn(_("resetting to regular file\n"));
-			INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT,
-			  &= ~(INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT));
-			INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT,
-			  |= INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFREG);
+			do_warn(_("correcting nextents for inode %llu, "
+				"was %d - counted %llu\n"), lino,
+				be32_to_cpu(dinoc->di_nextents), nextents);
+			dinoc->di_nextents = cpu_to_be32(nextents);
+			*dirty = 1;
 		} else  {
-			do_warn(_("would reset to regular file\n"));
-		}
-	}
-
-	/*
-	 * only regular files with REALTIME or EXTSIZE flags set can have
-	 * extsize set, or directories with EXTSZINHERIT.
-	 */
-	if (INT_GET(dinoc->di_extsize, ARCH_CONVERT) != 0)  {
-		if ((type == XR_INO_RTDATA) ||
-		    (type == XR_INO_DIR &&
-				(INT_GET(dinoc->di_flags, ARCH_CONVERT) &
-				 XFS_DIFLAG_EXTSZINHERIT)) ||
-		    (type == XR_INO_DATA &&
-				(INT_GET(dinoc->di_flags, ARCH_CONVERT) &
-				 XFS_DIFLAG_EXTSIZE)))  {
-			/* s'okay */ ;
-		} else {
-			do_warn(
-	_("bad non-zero extent size %u for non-realtime/extsize inode %llu, "),
-				INT_GET(dinoc->di_extsize, ARCH_CONVERT), lino);
-
-			if (!no_modify)  {
-				do_warn(_("resetting to zero\n"));
-				dinoc->di_extsize = 0;
-				*dirty = 1;
-			} else  {
-				do_warn(_("would reset to zero\n"));
-			}
+			do_warn(_("bad nextents %d for inode %llu, would reset "
+				"to %llu\n"), be32_to_cpu(dinoc->di_nextents),
+				lino, nextents);
 		}
 	}
 
-	/*
-	 * for realtime inodes, check sizes to see that
-	 * they are consistent with the # of realtime blocks.
-	 * also, verify that they contain only one extent and
-	 * are extent format files.  If anything's wrong, clear
-	 * the inode -- we'll recreate it in phase 6.
-	 */
-	if (do_rt &&
-	    ((lino == mp->m_sb.sb_rbmino &&
-	      INT_GET(dinoc->di_size, ARCH_CONVERT)
-			  != mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize) ||
-	     (lino == mp->m_sb.sb_rsumino &&
-	      INT_GET(dinoc->di_size, ARCH_CONVERT) != mp->m_rsumsize))) {
-
-		do_warn(_("bad size %llu for realtime %s inode %llu\n"),
-			INT_GET(dinoc->di_size, ARCH_CONVERT), rstring, lino);
-
-		if (!no_modify)  {
-			*dirty += clear_dinode(mp, dino, lino);
-			ASSERT(*dirty > 0);
-		}
-
-		*cleared = 1;
-		*used = is_free;
-		*isa_dir = 0;
-
-		return(1);
+	if (anextents > MAXAEXTNUM)  {
+		do_warn(_("too many attr fork extents (%llu) in inode %llu\n"),
+			anextents, lino);
+		return 1;
 	}
-
-	if (do_rt && mp->m_sb.sb_rblocks == 0 && INT_GET(dinoc->di_nextents, ARCH_CONVERT) != 0)  {
-		do_warn(_("bad # of extents (%u) for realtime %s inode %llu\n"),
-			INT_GET(dinoc->di_nextents, ARCH_CONVERT), rstring, lino);
-
+	if (anextents != be16_to_cpu(dinoc->di_anextents))  {
 		if (!no_modify)  {
-			*dirty += clear_dinode(mp, dino, lino);
-			ASSERT(*dirty > 0);
-		}
-
-		*cleared = 1;
-		*used = is_free;
-		*isa_dir = 0;
-
-		return(1);
-	}
-
-	/*
-	 * Setup nextents and anextents for blkmap_alloc calls.
-	 */
-	nextents = INT_GET(dinoc->di_nextents, ARCH_CONVERT);
-	if (nextents > INT_GET(dinoc->di_nblocks, ARCH_CONVERT) || nextents > XFS_MAX_INCORE_EXTENTS)
-		nextents = 1;
-	anextents = INT_GET(dinoc->di_anextents, ARCH_CONVERT);
-	if (anextents > INT_GET(dinoc->di_nblocks, ARCH_CONVERT) || anextents > XFS_MAX_INCORE_EXTENTS)
-		anextents = 1;
-
-	/*
-	 * general size/consistency checks:
-	 *
-	 * if the size <= size of the data fork, directories  must be
-	 * local inodes unlike regular files which would be extent inodes.
-	 * all the other mentioned types have to have a zero size value.
-	 *
-	 * if the size and format don't match, get out now rather than
-	 * risk trying to process a non-existent extents or btree
-	 * type data fork.
-	 */
-	switch (type)  {
-	case XR_INO_DIR:
-		if (INT_GET(dinoc->di_size, ARCH_CONVERT) <=
-			XFS_DFORK_DSIZE(dino, mp) &&
-		    (dinoc->di_format != XFS_DINODE_FMT_LOCAL))  {
-			do_warn(
-_("mismatch between format (%d) and size (%lld) in directory ino %llu\n"),
-				dinoc->di_format,
-				INT_GET(dinoc->di_size, ARCH_CONVERT),
-				lino);
-
-			if (!no_modify)  {
-				*dirty += clear_dinode(mp,
-						dino, lino);
-				ASSERT(*dirty > 0);
-			}
-
-			*cleared = 1;
-			*used = is_free;
-			*isa_dir = 0;
-
-			return(1);
-		}
-		if (dinoc->di_format != XFS_DINODE_FMT_LOCAL)
-			dblkmap = blkmap_alloc(nextents);
-		break;
-	case XR_INO_SYMLINK:
-		if (process_symlink_extlist(mp, lino, dino))  {
-			do_warn(_("bad data fork in symlink %llu\n"), lino);
-
-			if (!no_modify)  {
-				*dirty += clear_dinode(mp,
-						dino, lino);
-				ASSERT(*dirty > 0);
-			}
-
-			*cleared = 1;
-			*used = is_free;
-			*isa_dir = 0;
-
-			return(1);
-		}
-		if (dinoc->di_format != XFS_DINODE_FMT_LOCAL)
-			dblkmap = blkmap_alloc(nextents);
-		break;
-	case XR_INO_CHRDEV:	/* fall through to FIFO case ... */
-	case XR_INO_BLKDEV:	/* fall through to FIFO case ... */
-	case XR_INO_SOCK:	/* fall through to FIFO case ... */
-	case XR_INO_MOUNTPOINT:	/* fall through to FIFO case ... */
-	case XR_INO_FIFO:
-		if (process_misc_ino_types(mp, dino, lino, type))  {
-			if (!no_modify)  {
-				*dirty += clear_dinode(mp, dino, lino);
-				ASSERT(*dirty > 0);
-			}
-
-			*cleared = 1;
-			*used = is_free;
-			*isa_dir = 0;
-
-			return(1);
-		}
-		break;
-	case XR_INO_RTDATA:
-		/*
-		 * if we have no realtime blocks, any inode claiming
-		 * to be a real-time file is bogus
-		 */
-		if (mp->m_sb.sb_rblocks == 0)  {
-			do_warn(
-			_("found inode %llu claiming to be a real-time file\n"),
-				lino);
-
-			if (!no_modify)  {
-				*dirty += clear_dinode(mp, dino, lino);
-				ASSERT(*dirty > 0);
-			}
-
-			*cleared = 1;
-			*used = is_free;
-			*isa_dir = 0;
-
-			return(1);
-		}
-		break;
-	case XR_INO_RTBITMAP:
-		if (INT_GET(dinoc->di_size, ARCH_CONVERT) !=
-		    (__int64_t)mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize)  {
-			do_warn(
-	_("realtime bitmap inode %llu has bad size %lld (should be %lld)\n"),
-				lino, INT_GET(dinoc->di_size, ARCH_CONVERT),
-				(__int64_t) mp->m_sb.sb_rbmblocks *
-				mp->m_sb.sb_blocksize);
-
-			if (!no_modify)  {
-				*dirty += clear_dinode(mp, dino, lino);
-				ASSERT(*dirty > 0);
-			}
-
-			*cleared = 1;
-			*used = is_free;
-			*isa_dir = 0;
-
-			return(1);
-		}
-		dblkmap = blkmap_alloc(nextents);
-		break;
-	case XR_INO_RTSUM:
-		if (INT_GET(dinoc->di_size, ARCH_CONVERT) != mp->m_rsumsize)  {
-			do_warn(
-	_("realtime summary inode %llu has bad size %lld (should be %d)\n"),
-				lino, INT_GET(dinoc->di_size, ARCH_CONVERT),
-				mp->m_rsumsize);
-
-			if (!no_modify)  {
-				*dirty += clear_dinode(mp, dino, lino);
-				ASSERT(*dirty > 0);
-			}
-
-			*cleared = 1;
-			*used = is_free;
-			*isa_dir = 0;
-
-			return(1);
-		}
-		dblkmap = blkmap_alloc(nextents);
-		break;
-	default:
-		break;
-	}
-
-	/*
-	 * check for illegal values of forkoff
-	 */
-	err = 0;
-	if (dinoc->di_forkoff != 0)  {
-		switch (dinoc->di_format)  {
-		case XFS_DINODE_FMT_DEV:
-			if (dinoc->di_forkoff !=
-					(roundup(sizeof(xfs_dev_t), 8) >> 3))  {
-				do_warn(
-		_("bad attr fork offset %d in dev inode %llu, should be %d\n"),
-					(int) dinoc->di_forkoff,
-					lino,
-					(int) (roundup(sizeof(xfs_dev_t), 8) >> 3));
-				err = 1;
-			}
-			break;
-		case XFS_DINODE_FMT_UUID:
-			if (dinoc->di_forkoff !=
-					(roundup(sizeof(uuid_t), 8) >> 3))  {
-				do_warn(
-		_("bad attr fork offset %d in uuid inode %llu, should be %d\n"),
-					(int) dinoc->di_forkoff,
-					lino,
-					(int)(roundup(sizeof(uuid_t), 8) >> 3));
-				err = 1;
-			}
-			break;
-		case XFS_DINODE_FMT_LOCAL:	/* fall through ... */
-		case XFS_DINODE_FMT_EXTENTS:	/* fall through ... */
-		case XFS_DINODE_FMT_BTREE: {
-			if (dinoc->di_forkoff >= (XFS_LITINO(mp) >> 3))  {
-				do_warn(
-		_("bad attr fork offset %d in inode %llu, max=%d\n"),
-					(int) dinoc->di_forkoff,
-					lino, XFS_LITINO(mp) >> 3);
-				err = 1;
-			}
-			break;
-		    }
-		default:
-			do_error(_("unexpected inode format %d\n"),
-				(int) dinoc->di_format);
-			break;
+			do_warn(_("correcting anextents for inode %llu, "
+				"was %d - counted %llu\n"), lino,
+				be16_to_cpu(dinoc->di_anextents), anextents);
+			dinoc->di_anextents = cpu_to_be16(anextents);
+			*dirty = 1;
+		} else  {
+			do_warn(_("bad anextents %d for inode %llu, would reset"
+				" to %llu\n"), be16_to_cpu(dinoc->di_anextents),
+				lino, anextents);
 		}
 	}
+	return 0;
+}
 
-	if (err)  {
-		if (!no_modify)  {
-			*dirty += clear_dinode(mp, dino, lino);
-			ASSERT(*dirty > 0);
-		}
+/*
+ * check data fork -- if it's bad, clear the inode
+ */
+static int
+process_inode_data_fork(
+	xfs_mount_t	*mp,
+	xfs_agnumber_t	agno,
+	xfs_agino_t	ino,
+	xfs_dinode_t	*dino,
+	int		type,
+	int		*dirty,
+	xfs_drfsbno_t	*totblocks,
+	__uint64_t	*nextents,
+	blkmap_t	**dblkmap,
+	int		check_dups)
+{
+	xfs_dinode_core_t *dinoc = &dino->di_core;
+	xfs_ino_t	lino = XFS_AGINO_TO_INO(mp, agno, ino);
+	int		err = 0;
 
-		*cleared = 1;
-		*used = is_free;
-		*isa_dir = 0;
-		blkmap_free(dblkmap);
-		return(1);
-	}
+	*nextents = be32_to_cpu(dinoc->di_nextents);
+	if (*nextents > be64_to_cpu(dinoc->di_nblocks) ||
+			*nextents > XFS_MAX_INCORE_EXTENTS)
+		*nextents = 1;
+
+	if (dinoc->di_format != XFS_DINODE_FMT_LOCAL && type != XR_INO_RTDATA)
+		*dblkmap = blkmap_alloc(*nextents);
+	*nextents = 0;
 
-	/*
-	 * check data fork -- if it's bad, clear the inode
-	 */
-	nextents = 0;
 	switch (dinoc->di_format) {
 	case XFS_DINODE_FMT_LOCAL:
-		err = process_lclinode(mp, agno, ino, dino, type,
-			dirty, &totblocks, &nextents, &dblkmap,
-			XFS_DATA_FORK, check_dups);
+		err = process_lclinode(mp, agno, ino, dino, type, dirty,
+			totblocks, nextents, dblkmap, XFS_DATA_FORK,
+			check_dups);
 		break;
 	case XFS_DINODE_FMT_EXTENTS:
-		err = process_exinode(mp, agno, ino, dino, type,
-			dirty, &totblocks, &nextents, &dblkmap,
-			XFS_DATA_FORK, check_dups);
+		err = process_exinode(mp, agno, ino, dino, type, dirty,
+			totblocks, nextents, dblkmap, XFS_DATA_FORK,
+			check_dups);
 		break;
 	case XFS_DINODE_FMT_BTREE:
-		err = process_btinode(mp, agno, ino, dino, type,
-			dirty, &totblocks, &nextents, &dblkmap,
-			XFS_DATA_FORK, check_dups);
+		err = process_btinode(mp, agno, ino, dino, type, dirty,
+			totblocks, nextents, dblkmap, XFS_DATA_FORK,
+			check_dups);
 		break;
 	case XFS_DINODE_FMT_DEV:	/* fall through */
-	case XFS_DINODE_FMT_UUID:
 		err = 0;
 		break;
 	default:
 		do_error(_("unknown format %d, ino %llu (mode = %d)\n"),
-			dinoc->di_format, lino,
-			INT_GET(dinoc->di_mode, ARCH_CONVERT));
+			dinoc->di_format, lino, be16_to_cpu(dinoc->di_mode));
 	}
 
 	if (err)  {
-		/*
-		 * problem in the data fork, clear out the inode
-		 * and get out
-		 */
 		do_warn(_("bad data fork in inode %llu\n"), lino);
-
 		if (!no_modify)  {
 			*dirty += clear_dinode(mp, dino, lino);
 			ASSERT(*dirty > 0);
 		}
-
-		*cleared = 1;
-		*used = is_free;
-		*isa_dir = 0;
-		blkmap_free(dblkmap);
-		return(1);
+		return 1;
 	}
 
 	if (check_dups)  {
@@ -2486,465 +2168,635 @@
 		switch (dinoc->di_format) {
 		case XFS_DINODE_FMT_LOCAL:
 			err = process_lclinode(mp, agno, ino, dino, type,
-				dirty, &totblocks, &nextents, &dblkmap,
+				dirty, totblocks, nextents, dblkmap,
 				XFS_DATA_FORK, 0);
 			break;
 		case XFS_DINODE_FMT_EXTENTS:
 			err = process_exinode(mp, agno, ino, dino, type,
-				dirty, &totblocks, &nextents, &dblkmap,
+				dirty, totblocks, nextents, dblkmap,
 				XFS_DATA_FORK, 0);
 			break;
 		case XFS_DINODE_FMT_BTREE:
 			err = process_btinode(mp, agno, ino, dino, type,
-				dirty, &totblocks, &nextents, &dblkmap,
+				dirty, totblocks, nextents, dblkmap,
 				XFS_DATA_FORK, 0);
 			break;
 		case XFS_DINODE_FMT_DEV:	/* fall through */
-		case XFS_DINODE_FMT_UUID:
 			err = 0;
 			break;
 		default:
 			do_error(_("unknown format %d, ino %llu (mode = %d)\n"),
 				dinoc->di_format, lino,
-				INT_GET(dinoc->di_mode, ARCH_CONVERT));
+				be16_to_cpu(dinoc->di_mode));
 		}
 
-		if (no_modify && err != 0)  {
-			*cleared = 1;
-			*used = is_free;
-			*isa_dir = 0;
-			blkmap_free(dblkmap);
-			return(1);
-		}
+		if (no_modify && err != 0)
+			return 1;
 
 		ASSERT(err == 0);
 	}
+	return 0;
+}
 
-	/*
-	 * check attribute fork if necessary.  attributes are
-	 * always stored in the regular filesystem.
-	 */
+/*
+ * Process extended attribute fork in inode
+ */
+static int
+process_inode_attr_fork(
+	xfs_mount_t	*mp,
+	xfs_agnumber_t	agno,
+	xfs_agino_t	ino,
+	xfs_dinode_t	*dino,
+	int		type,
+	int		*dirty,
+	xfs_drfsbno_t	*atotblocks,
+	__uint64_t	*anextents,
+	int		check_dups,
+	int		extra_attr_check,
+	int		*retval)
+{
+	xfs_dinode_core_t *dinoc = &dino->di_core;
+	xfs_ino_t	lino = XFS_AGINO_TO_INO(mp, agno, ino);
+	blkmap_t	*ablkmap = NULL;
+	int		repair = 0;
+	int		err;
+
+	if (!XFS_DFORK_Q(dino)) {
+		*anextents = 0;
+		if (dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) {
+			do_warn(_("bad attribute format %d in inode %llu, "),
+				dinoc->di_aformat, lino);
+			if (!no_modify) {
+				do_warn(_("resetting value\n"));
+				dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS;
+				*dirty = 1;
+			} else
+				do_warn(_("would reset value\n"));
+		}
+		return 0;
+	}
 
-	if (!XFS_DFORK_Q(dino) &&
-	    dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) {
-		do_warn(_("bad attribute format %d in inode %llu, "),
-			dinoc->di_aformat, lino);
-		if (!no_modify) {
-			do_warn(_("resetting value\n"));
-			dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS;
-			*dirty = 1;
-		} else
-			do_warn(_("would reset value\n"));
-		anextents = 0;
-	} else if (XFS_DFORK_Q(dino)) {
+	*anextents = be16_to_cpu(dinoc->di_anextents);
+	if (*anextents > be64_to_cpu(dinoc->di_nblocks) ||
+			*anextents > XFS_MAX_INCORE_EXTENTS)
+		*anextents = 1;
+
+	switch (dinoc->di_aformat) {
+	case XFS_DINODE_FMT_LOCAL:
+		*anextents = 0;
+		err = process_lclinode(mp, agno, ino, dino, type, dirty,
+				atotblocks, anextents, &ablkmap,
+				XFS_ATTR_FORK, check_dups);
+		break;
+	case XFS_DINODE_FMT_EXTENTS:
+		ablkmap = blkmap_alloc(*anextents);
+		*anextents = 0;
+		err = process_exinode(mp, agno, ino, dino, type, dirty,
+				atotblocks, anextents, &ablkmap,
+				XFS_ATTR_FORK, check_dups);
+		break;
+	case XFS_DINODE_FMT_BTREE:
+		ablkmap = blkmap_alloc(*anextents);
+		*anextents = 0;
+		err = process_btinode(mp, agno, ino, dino, type, dirty,
+				atotblocks, anextents, &ablkmap,
+				XFS_ATTR_FORK, check_dups);
+		break;
+	default:
+		do_warn(_("illegal attribute format %d, ino %llu\n"),
+				dinoc->di_aformat, lino);
+		err = 1;
+		break;
+	}
+
+	if (err) {
+		/*
+		 * clear the attribute fork if necessary.  we can't
+		 * clear the inode because we've already put the
+		 * inode space info into the blockmap.
+		 *
+		 * XXX - put the inode onto the "move it" list and
+		 *	log the the attribute scrubbing
+		 */
+		do_warn(_("bad attribute fork in inode %llu"), lino);
+
+		if (!no_modify)  {
+			if (delete_attr_ok)  {
+				do_warn(_(", clearing attr fork\n"));
+				*dirty += clear_dinode_attr(mp, dino, lino);
+				dinoc->di_aformat = XFS_DINODE_FMT_LOCAL;
+			} else  {
+				do_warn("\n");
+				*dirty += clear_dinode(mp, dino, lino);
+			}
+			ASSERT(*dirty > 0);
+		} else  {
+			do_warn(_(", would clear attr fork\n"));
+		}
+
+		*atotblocks = 0;
+		*anextents = 0;
+		blkmap_free(ablkmap);
+		*retval = 1;
+
+		return delete_attr_ok ? 0 : 1;
+	}
+
+	if (check_dups)  {
 		switch (dinoc->di_aformat) {
 		case XFS_DINODE_FMT_LOCAL:
-			anextents = 0;
 			err = process_lclinode(mp, agno, ino, dino,
-				type, dirty, &atotblocks, &anextents, &ablkmap,
-				XFS_ATTR_FORK, check_dups);
+				type, dirty, atotblocks, anextents,
+				&ablkmap, XFS_ATTR_FORK, 0);
 			break;
 		case XFS_DINODE_FMT_EXTENTS:
-			ablkmap = blkmap_alloc(anextents);
-			anextents = 0;
 			err = process_exinode(mp, agno, ino, dino,
-				type, dirty, &atotblocks, &anextents, &ablkmap,
-				XFS_ATTR_FORK, check_dups);
+				type, dirty, atotblocks, anextents,
+				&ablkmap, XFS_ATTR_FORK, 0);
 			break;
 		case XFS_DINODE_FMT_BTREE:
-			ablkmap = blkmap_alloc(anextents);
-			anextents = 0;
 			err = process_btinode(mp, agno, ino, dino,
-				type, dirty, &atotblocks, &anextents, &ablkmap,
-				XFS_ATTR_FORK, check_dups);
+				type, dirty, atotblocks, anextents,
+				&ablkmap, XFS_ATTR_FORK, 0);
 			break;
 		default:
-			anextents = 0;
-			do_warn(_("illegal attribute format %d, ino %llu\n"),
-					dinoc->di_aformat, lino);
-			err = 1;
-			break;
+			do_error(_("illegal attribute fmt %d, ino %llu\n"),
+				dinoc->di_aformat, lino);
 		}
 
-		if (err)  {
-			/*
-			 * clear the attribute fork if necessary.  we can't
-			 * clear the inode because we've already put the
-			 * inode space info into the blockmap.
-			 *
-			 * XXX - put the inode onto the "move it" list and
-			 *	log the the attribute scrubbing
-			 */
-			do_warn(_("bad attribute fork in inode %llu"), lino);
+		if (no_modify && err != 0) {
+			blkmap_free(ablkmap);
+			return 1;
+		}
 
+		ASSERT(err == 0);
+	}
+
+	/*
+	 * do attribute semantic-based consistency checks now
+	 */
+
+	/* get this only in phase 3, not in both phase 3 and 4 */
+	if (extra_attr_check &&
+			process_attributes(mp, lino, dino, ablkmap, &repair)) {
+		do_warn(_("problem with attribute contents in inode %llu\n"),
+			lino);
+		if (!repair) {
+			/* clear attributes if not done already */
 			if (!no_modify)  {
-				if (delete_attr_ok)  {
-					do_warn(_(", clearing attr fork\n"));
-					*dirty += clear_dinode_attr(mp,
-							dino, lino);
-				} else  {
-					do_warn("\n");
-					*dirty += clear_dinode(mp,
-							dino, lino);
-				}
-				ASSERT(*dirty > 0);
+				*dirty += clear_dinode_attr(mp, dino, lino);
+				dinoc->di_aformat = XFS_DINODE_FMT_LOCAL;
 			} else  {
-				do_warn(_(", would clear attr fork\n"));
+				do_warn(_("would clear attr fork\n"));
 			}
+			*atotblocks = 0;
+			*anextents = 0;
+		}
+		else {
+			*dirty = 1; /* it's been repaired */
+		}
+	}
+	blkmap_free(ablkmap);
+	return 0;
+}
 
-			atotblocks = 0;
-			anextents = 0;
+/*
+ * check nlinks feature, if it's a version 1 inode,
+ * just leave nlinks alone.  even if it's set wrong,
+ * it'll be reset when read in.
+ */
 
-			if (delete_attr_ok)  {
-				if (!no_modify)
-					dinoc->di_aformat = XFS_DINODE_FMT_LOCAL;
+static int
+process_check_inode_nlink_version(
+	xfs_dinode_core_t *dinoc,
+	xfs_ino_t	lino)
+{
+	int		dirty = 0;
+
+	if (dinoc->di_version > XFS_DINODE_VERSION_1 && !fs_inode_nlink)  {
+		/*
+		 * do we have a fs/inode version mismatch with a valid
+		 * version 2 inode here that has to stay version 2 or
+		 * lose links?
+		 */
+		if (be32_to_cpu(dinoc->di_nlink) > XFS_MAXLINK_1)  {
+			/*
+			 * yes.  are nlink inodes allowed?
+			 */
+			if (fs_inode_nlink_allowed)  {
+				/*
+				 * yes, update status variable which will
+				 * cause sb to be updated later.
+				 */
+				fs_inode_nlink = 1;
+				do_warn(_("version 2 inode %llu claims > %u links, "),
+					lino, XFS_MAXLINK_1);
+				if (!no_modify)  {
+					do_warn(_("updating superblock "
+						"version number\n"));
+				} else  {
+					do_warn(_("would update superblock "
+						"version number\n"));
+				}
 			} else  {
-				*cleared = 1;
-				*used = is_free;
-				*isa_dir = 0;
-				blkmap_free(dblkmap);
-				blkmap_free(ablkmap);
+				/*
+				 * no, have to convert back to onlinks
+				 * even if we lose some links
+				 */
+				do_warn(_("WARNING:  version 2 inode %llu "
+					"claims > %u links, "),
+					lino, XFS_MAXLINK_1);
+				if (!no_modify)  {
+					do_warn(_("converting back to version 1,\n"
+						"this may destroy %d links\n"),
+						be32_to_cpu(dinoc->di_nlink) -
+							XFS_MAXLINK_1);
+
+					dinoc->di_version = XFS_DINODE_VERSION_1;
+					dinoc->di_nlink = cpu_to_be32(XFS_MAXLINK_1);
+					dinoc->di_onlink = cpu_to_be16(XFS_MAXLINK_1);
+					dirty = 1;
+				} else  {
+					do_warn(_("would convert back to version 1,\n"
+						"\tthis might destroy %d links\n"),
+						be32_to_cpu(dinoc->di_nlink) -
+							XFS_MAXLINK_1);
+				}
 			}
-			return(1);
-
-		} else if (check_dups)  {
-			switch (dinoc->di_aformat) {
-			case XFS_DINODE_FMT_LOCAL:
-				err = process_lclinode(mp, agno, ino, dino,
-					type, dirty, &atotblocks, &anextents,
-					&ablkmap, XFS_ATTR_FORK, 0);
-				break;
-			case XFS_DINODE_FMT_EXTENTS:
-				err = process_exinode(mp, agno, ino, dino,
-					type, dirty, &atotblocks, &anextents,
-					&ablkmap, XFS_ATTR_FORK, 0);
-				break;
-			case XFS_DINODE_FMT_BTREE:
-				err = process_btinode(mp, agno, ino, dino,
-					type, dirty, &atotblocks, &anextents,
-					&ablkmap, XFS_ATTR_FORK, 0);
-				break;
-			default:
-				do_error(
-				_("illegal attribute fmt %d, ino %llu\n"),
-					dinoc->di_aformat, lino);
+		} else  {
+			/*
+			 * do we have a v2 inode that we could convert back
+			 * to v1 without losing any links?  if we do and
+			 * we have a mismatch between superblock bits and the
+			 * version bit, alter the version bit in this case.
+			 *
+			 * the case where we lost links was handled above.
+			 */
+			do_warn(_("found version 2 inode %llu, "), lino);
+			if (!no_modify)  {
+				do_warn(_("converting back to version 1\n"));
+				dinoc->di_version = XFS_DINODE_VERSION_1;
+				dinoc->di_onlink = cpu_to_be16(
+					be32_to_cpu(dinoc->di_nlink));
+				dirty = 1;
+			} else  {
+				do_warn(_("would convert back to version 1\n"));
 			}
+		}
+	}
+
+	/*
+	 * ok, if it's still a version 2 inode, it's going
+	 * to stay a version 2 inode.  it should have a zero
+	 * onlink field, so clear it.
+	 */
+	if (dinoc->di_version > XFS_DINODE_VERSION_1 &&
+			dinoc->di_onlink != 0 && fs_inode_nlink > 0) {
+		if (!no_modify) {
+			do_warn(_("clearing obsolete nlink field in "
+				"version 2 inode %llu, was %d, now 0\n"),
+				lino, be16_to_cpu(dinoc->di_onlink));
+			dinoc->di_onlink = 0;
+			dirty = 1;
+		} else  {
+			do_warn(_("would clear obsolete nlink field in "
+				"version 2 inode %llu, currently %d\n"),
+				lino, be16_to_cpu(dinoc->di_onlink));
+		}
+	}
+	return dirty;
+}
+
+/*
+ * returns 0 if the inode is ok, 1 if the inode is corrupt
+ * check_dups can be set to 1 *only* when called by the
+ * first pass of the duplicate block checking of phase 4.
+ * *dirty is set > 0 if the dinode has been altered and
+ * needs to be written out.
+ *
+ * for detailed, info, look at process_dinode() comments.
+ */
+/* ARGSUSED */
+int
+process_dinode_int(xfs_mount_t *mp,
+		xfs_dinode_t *dino,
+		xfs_agnumber_t agno,
+		xfs_agino_t ino,
+		int was_free,		/* 1 if inode is currently free */
+		int *dirty,		/* out == > 0 if inode is now dirty */
+		int *used,		/* out == 1 if inode is in use */
+		int verify_mode,	/* 1 == verify but don't modify inode */
+		int uncertain,		/* 1 == inode is uncertain */
+		int ino_discovery,	/* 1 == check dirs for unknown inodes */
+		int check_dups,		/* 1 == check if inode claims
+					 * duplicate blocks		*/
+		int extra_attr_check, /* 1 == do attribute format and value checks */
+		int *isa_dir,		/* out == 1 if inode is a directory */
+		xfs_ino_t *parent)	/* out -- parent if ino is a dir */
+{
+	xfs_drfsbno_t		totblocks = 0;
+	xfs_drfsbno_t		atotblocks = 0;
+	xfs_dinode_core_t	*dinoc;
+	int			di_mode;
+	int			type;
+	int			retval = 0;
+	__uint64_t		nextents;
+	__uint64_t		anextents;
+	xfs_ino_t		lino;
+	const int		is_free = 0;
+	const int		is_used = 1;
+	blkmap_t		*dblkmap = NULL;
+
+	*dirty = *isa_dir = 0;
+	*used = is_used;
+	type = XR_INO_UNKNOWN;
+
+	dinoc = &dino->di_core;
+	lino = XFS_AGINO_TO_INO(mp, agno, ino);
+	di_mode = be16_to_cpu(dinoc->di_mode);
+
+	/*
+	 * if in verify mode, don't modify the inode.
+	 *
+	 * if correcting, reset stuff that has known values
+	 *
+	 * if in uncertain mode, be silent on errors since we're
+	 * trying to find out if these are inodes as opposed
+	 * to assuming that they are.  Just return the appropriate
+	 * return code in that case.
+	 *
+	 * If uncertain is set, verify_mode MUST be set.
+	 */
+	ASSERT(uncertain == 0 || verify_mode != 0);
+
+	if (be16_to_cpu(dinoc->di_magic) != XFS_DINODE_MAGIC)  {
+		retval = 1;
+		if (!uncertain)
+			do_warn(_("bad magic number 0x%x on inode %llu%c"),
+				be16_to_cpu(dinoc->di_magic), lino,
+				verify_mode ? '\n' : ',');
+		if (!verify_mode) {
+			if (!no_modify)  {
+				do_warn(_(" resetting magic number\n"));
+				dinoc->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
+				*dirty = 1;
+			} else
+				do_warn(_(" would reset magic number\n"));
+		}
+	}
+
+	if (!XFS_DINODE_GOOD_VERSION(dinoc->di_version) ||
+	    (!fs_inode_nlink && dinoc->di_version > XFS_DINODE_VERSION_1))  {
+		retval = 1;
+		if (!uncertain)
+			do_warn(_("bad version number 0x%x on inode %llu%c"),
+				dinoc->di_version, lino,
+				verify_mode ? '\n' : ',');
+		if (!verify_mode) {
+			if (!no_modify) {
+				do_warn(_(" resetting version number\n"));
+				dinoc->di_version = (fs_inode_nlink) ?
+					XFS_DINODE_VERSION_2 :
+					XFS_DINODE_VERSION_1;
+				*dirty = 1;
+			} else
+				do_warn(_(" would reset version number\n"));
+		}
+	}
+
+	/*
+	 * blow out of here if the inode size is < 0
+	 */
+	if ((xfs_fsize_t)be64_to_cpu(dinoc->di_size) < 0)  {
+		if (!uncertain)
+			do_warn(_("bad (negative) size %lld on inode %llu\n"),
+				be64_to_cpu(dinoc->di_size), lino);
+		if (verify_mode)
+			return 1;
+		goto clear_bad_out;
+	}
+
+	/*
+	 * if not in verify mode, check to sii if the inode and imap
+	 * agree that the inode is free
+	 */
+	if (!verify_mode && di_mode == 0) {
+		/*
+		 * was_free value is not meaningful if we're in verify mode
+		 */
+		if (was_free) {
+			/*
+			 * easy case, inode free -- inode and map agree, clear
+			 * it just in case to ensure that format, etc. are
+			 * set correctly
+			 */
+			if (!no_modify)
+				*dirty += clear_dinode(mp, dino, lino);
+			*used = is_free;
+			return 0;
+		}
+		/*
+		 * the inode looks free but the map says it's in use.
+		 * clear the inode just to be safe and mark the inode
+		 * free.
+		 */
+		do_warn(_("imap claims a free inode %llu is in use, "), lino);
+		if (!no_modify)  {
+			do_warn(_("correcting imap and clearing inode\n"));
+			*dirty += clear_dinode(mp, dino, lino);
+			retval = 1;
+		} else
+			do_warn(_("would correct imap and clear inode\n"));
+		*used = is_free;
+		return retval;
+	}
 
-			if (no_modify && err != 0)  {
-				*cleared = 1;
-				*used = is_free;
-				*isa_dir = 0;
-				blkmap_free(dblkmap);
-				blkmap_free(ablkmap);
-				return(1);
-			}
+	/*
+	 * because of the lack of any write ordering guarantee, it's
+	 * possible that the core got updated but the forks didn't.
+	 * so rather than be ambitious (and probably incorrect),
+	 * if there's an inconsistency, we get conservative and
+	 * just pitch the file.  blow off checking formats of
+	 * free inodes since technically any format is legal
+	 * as we reset the inode when we re-use it.
+	 */
+	if (di_mode != 0 && check_dinode_mode_format(dinoc) != 0) {
+		if (!uncertain)
+			do_warn(_("bad inode format in inode %llu\n"), lino);
+		if (verify_mode)
+			return 1;
+		goto clear_bad_out;
+	}
 
-			ASSERT(err == 0);
-		}
+	if (verify_mode)
+		return retval;
 
-		/*
-		 * do attribute semantic-based consistency checks now
-		 */
+	/*
+	 * clear the next unlinked field if necessary on a good
+	 * inode only during phase 4 -- when checking for inodes
+	 * referencing duplicate blocks.  then it's safe because
+	 * we've done the inode discovery and have found all the inodes
+	 * we're going to find.  check_dups is set to 1 only during
+	 * phase 4.  Ugly.
+	 */
+	if (check_dups && !no_modify)
+		*dirty += clear_dinode_unlinked(mp, dino);
 
-		/* get this only in phase 3, not in both phase 3 and 4 */
-		if (extra_attr_check) {
-		    if ((err = process_attributes(mp, lino, dino, ablkmap,
-				    &repair))) {
-			    do_warn(
-		_("problem with attribute contents in inode %llu\n"), lino);
-			    if(!repair) {
-				    /* clear attributes if not done already */
-				    if (!no_modify)  {
-					    *dirty += clear_dinode_attr(
-							mp, dino, lino);
-					    dinoc->di_aformat =
-						XFS_DINODE_FMT_LOCAL;
-				    } else  {
-					    do_warn(
-					_("would clear attr fork\n"));
-				    }
-				    atotblocks = 0;
-				    anextents = 0;
-			    }
-			    else {
-				    *dirty = 1; /* it's been repaired */
-			     }
-		    }
-		}
-		blkmap_free(ablkmap);
+	/* set type and map type info */
 
-	} else
-		anextents = 0;
+	switch (di_mode & S_IFMT) {
+	case S_IFDIR:
+		type = XR_INO_DIR;
+		*isa_dir = 1;
+		break;
+	case S_IFREG:
+		if (be16_to_cpu(dinoc->di_flags) & XFS_DIFLAG_REALTIME)
+			type = XR_INO_RTDATA;
+		else if (lino == mp->m_sb.sb_rbmino)
+			type = XR_INO_RTBITMAP;
+		else if (lino == mp->m_sb.sb_rsumino)
+			type = XR_INO_RTSUM;
+		else
+			type = XR_INO_DATA;
+		break;
+	case S_IFLNK:
+		type = XR_INO_SYMLINK;
+		break;
+	case S_IFCHR:
+		type = XR_INO_CHRDEV;
+		break;
+	case S_IFBLK:
+		type = XR_INO_BLKDEV;
+		break;
+	case S_IFSOCK:
+		type = XR_INO_SOCK;
+		break;
+	case S_IFIFO:
+		type = XR_INO_FIFO;
+		break;
+	default:
+		do_warn(_("bad inode type %#o inode %llu\n"),
+				di_mode & S_IFMT, lino);
+		goto clear_bad_out;
+	}
 
 	/*
-	* enforce totblocks is 0 for misc types
-	*/
-	if (process_misc_ino_types_blocks(totblocks, lino, type)) {
-		if (!no_modify)  {
-			*dirty += clear_dinode(mp, dino, lino);
-			ASSERT(*dirty > 0);
-		}
-		*cleared = 1;
-		*used = is_free;
-		*isa_dir = 0;
-		blkmap_free(dblkmap);
-		return(1);
-	}
+	 * type checks for superblock inodes
+	 */
+	if (process_check_sb_inodes(mp, dinoc, lino, &type, dirty) != 0)
+		goto clear_bad_out;
 
 	/*
-	 * correct space counters if required
+	 * only regular files with REALTIME or EXTSIZE flags set can have
+	 * extsize set, or directories with EXTSZINHERIT.
 	 */
-	if (totblocks + atotblocks != INT_GET(dinoc->di_nblocks, ARCH_CONVERT))  {
-		if (!no_modify)  {
-			do_warn(
-	_("correcting nblocks for inode %llu, was %llu - counted %llu\n"),
-				lino, INT_GET(dinoc->di_nblocks, ARCH_CONVERT),
-				totblocks + atotblocks);
-			*dirty = 1;
-			INT_SET(dinoc->di_nblocks, ARCH_CONVERT, totblocks + atotblocks);
-		} else  {
-			do_warn(
-	_("bad nblocks %llu for inode %llu, would reset to %llu\n"),
-				INT_GET(dinoc->di_nblocks, ARCH_CONVERT), lino,
-				totblocks + atotblocks);
+	if (dinoc->di_extsize) {
+		if ((type == XR_INO_RTDATA) ||
+		    (type == XR_INO_DIR && (be16_to_cpu(dinoc->di_flags) &
+					XFS_DIFLAG_EXTSZINHERIT)) ||
+		    (type == XR_INO_DATA && (be16_to_cpu(dinoc->di_flags) &
+				 XFS_DIFLAG_EXTSIZE)))  {
+			/* s'okay */ ;
+		} else {
+			do_warn(_("bad non-zero extent size %u for "
+					"non-realtime/extsize inode %llu, "),
+					be32_to_cpu(dinoc->di_extsize), lino);
+			if (!no_modify)  {
+				do_warn(_("resetting to zero\n"));
+				dinoc->di_extsize = 0;
+				*dirty = 1;
+			} else
+				do_warn(_("would reset to zero\n"));
 		}
 	}
 
-	if (nextents > MAXEXTNUM)  {
-		do_warn(_("too many data fork extents (%llu) in inode %llu\n"),
-			nextents, lino);
+	/*
+	 * general size/consistency checks:
+	 */
+	if (process_check_inode_sizes(mp, dino, lino, type) != 0)
+		goto clear_bad_out;
 
-		if (!no_modify)  {
-			*dirty += clear_dinode(mp, dino, lino);
-			ASSERT(*dirty > 0);
-		}
-		*cleared = 1;
-		*used = is_free;
-		*isa_dir = 0;
-		blkmap_free(dblkmap);
+	/*
+	 * check for illegal values of forkoff
+	 */
+	if (process_check_inode_forkoff(mp, dinoc, lino) != 0)
+		goto clear_bad_out;
 
-		return(1);
-	}
-	if (nextents != INT_GET(dinoc->di_nextents, ARCH_CONVERT))  {
-		if (!no_modify)  {
-			do_warn(
-	_("correcting nextents for inode %llu, was %d - counted %llu\n"),
-				lino, INT_GET(dinoc->di_nextents, ARCH_CONVERT),
-				nextents);
-			*dirty = 1;
-			INT_SET(dinoc->di_nextents, ARCH_CONVERT,
-				(xfs_extnum_t) nextents);
-		} else  {
-			do_warn(
-		_("bad nextents %d for inode %llu, would reset to %llu\n"),
-				INT_GET(dinoc->di_nextents, ARCH_CONVERT),
-				lino, nextents);
-		}
-	}
+	/*
+	 * check data fork -- if it's bad, clear the inode
+	 */
+	if (process_inode_data_fork(mp, agno, ino, dino, type, dirty,
+			&totblocks, &nextents, &dblkmap, check_dups) != 0)
+		goto bad_out;
 
-	if (anextents > MAXAEXTNUM)  {
-		do_warn(_("too many attr fork extents (%llu) in inode %llu\n"),
-			anextents, lino);
+	/*
+	 * check attribute fork if necessary.  attributes are
+	 * always stored in the regular filesystem.
+	 */
+	if (process_inode_attr_fork(mp, agno, ino, dino, type, dirty,
+			&atotblocks, &anextents, check_dups, extra_attr_check,
+			&retval))
+		goto bad_out;
 
-		if (!no_modify)  {
-			*dirty += clear_dinode(mp, dino, lino);
-			ASSERT(*dirty > 0);
-		}
-		*cleared = 1;
-		*used = is_free;
-		*isa_dir = 0;
-		blkmap_free(dblkmap);
-		return(1);
-	}
-	if (anextents != INT_GET(dinoc->di_anextents, ARCH_CONVERT))  {
-		if (!no_modify)  {
-			do_warn(
-	_("correcting anextents for inode %llu, was %d - counted %llu\n"),
-				lino,
-				INT_GET(dinoc->di_anextents, ARCH_CONVERT),
-				anextents);
-			*dirty = 1;
-			INT_SET(dinoc->di_anextents, ARCH_CONVERT,
-				(xfs_aextnum_t) anextents);
-		} else  {
-			do_warn(
-		_("bad anextents %d for inode %llu, would reset to %llu\n"),
-				INT_GET(dinoc->di_anextents, ARCH_CONVERT),
-				lino, anextents);
-		}
-	}
+	/*
+	 * enforce totblocks is 0 for misc types
+	 */
+	if (process_misc_ino_types_blocks(totblocks, lino, type))
+		goto clear_bad_out;
+
+	/*
+	 * correct space counters if required
+	 */
+	if (process_inode_blocks_and_extents(dinoc, totblocks + atotblocks,
+			nextents, anextents, lino, dirty) != 0)
+		goto clear_bad_out;
 
 	/*
 	 * do any semantic type-based checking here
 	 */
 	switch (type)  {
 	case XR_INO_DIR:
-		if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
-			err = process_dir2(mp, lino, dino, ino_discovery,
-					dirty, "", parent, dblkmap);
-		else
-			err = process_dir(mp, lino, dino, ino_discovery,
-					dirty, "", parent, dblkmap);
-		if (err)
-			do_warn(
-			_("problem with directory contents in inode %llu\n"),
-				lino);
-		break;
-	case XR_INO_RTBITMAP:
-		/* process_rtbitmap XXX */
-		err = 0;
-		break;
-	case XR_INO_RTSUM:
-		/* process_rtsummary XXX */
-		err = 0;
+		if (process_dir2(mp, lino, dino, ino_discovery, dirty, "",
+				parent, dblkmap) != 0) {
+			do_warn(_("problem with directory contents in "
+				"inode %llu\n"), lino);
+			goto clear_bad_out;
+		}
 		break;
 	case XR_INO_SYMLINK:
-		if ((err = process_symlink(mp, lino, dino, dblkmap)))
+		if (process_symlink(mp, lino, dino, dblkmap) != 0) {
 			do_warn(_("problem with symbolic link in inode %llu\n"),
 				lino);
-		break;
-	case XR_INO_DATA:	/* fall through to FIFO case ... */
-	case XR_INO_RTDATA:	/* fall through to FIFO case ... */
-	case XR_INO_CHRDEV:	/* fall through to FIFO case ... */
-	case XR_INO_BLKDEV:	/* fall through to FIFO case ... */
-	case XR_INO_SOCK:	/* fall through to FIFO case ... */
-	case XR_INO_FIFO:
-		err = 0;
+			goto clear_bad_out;
+		}
 		break;
 	default:
-		printf(_("Unexpected inode type\n"));
-		abort();
+		break;
 	}
 
 	if (dblkmap)
 		blkmap_free(dblkmap);
 
-	if (err)  {
-		/*
-		 * problem in the inode type-specific semantic
-		 * checking, clear out the inode and get out
-		 */
-		if (!no_modify)  {
-			*dirty += clear_dinode(mp, dino, lino);
-			ASSERT(*dirty > 0);
-		}
-		*cleared = 1;
-		*used = is_free;
-		*isa_dir = 0;
-
-		return(1);
-	}
-
 	/*
 	 * check nlinks feature, if it's a version 1 inode,
 	 * just leave nlinks alone.  even if it's set wrong,
 	 * it'll be reset when read in.
 	 */
-	if (dinoc->di_version > XFS_DINODE_VERSION_1 && !fs_inode_nlink)  {
-		/*
-		 * do we have a fs/inode version mismatch with a valid
-		 * version 2 inode here that has to stay version 2 or
-		 * lose links?
-		 */
-		if (INT_GET(dinoc->di_nlink, ARCH_CONVERT) > XFS_MAXLINK_1)  {
-			/*
-			 * yes.  are nlink inodes allowed?
-			 */
-			if (fs_inode_nlink_allowed)  {
-				/*
-				 * yes, update status variable which will
-				 * cause sb to be updated later.
-				 */
-				fs_inode_nlink = 1;
-				do_warn(
-				_("version 2 inode %llu claims > %u links, "),
-					lino, XFS_MAXLINK_1);
-				if (!no_modify)  {
-					do_warn(
-			_("updating superblock version number\n"));
-				} else  {
-					do_warn(
-			_("would update superblock version number\n"));
-				}
-			} else  {
-				/*
-				 * no, have to convert back to onlinks
-				 * even if we lose some links
-				 */
-				do_warn(
-			_("WARNING:  version 2 inode %llu claims > %u links, "),
-					lino, XFS_MAXLINK_1);
-				if (!no_modify)  {
-					do_warn(
-	_("converting back to version 1,\n\tthis may destroy %d links\n"),
-						INT_GET(dinoc->di_nlink,
-							ARCH_CONVERT)
-						- XFS_MAXLINK_1);
-
-					dinoc->di_version =
-						XFS_DINODE_VERSION_1;
-					INT_SET(dinoc->di_nlink, ARCH_CONVERT,
-						XFS_MAXLINK_1);
-					INT_SET(dinoc->di_onlink, ARCH_CONVERT,
-						XFS_MAXLINK_1);
-
-					*dirty = 1;
-				} else  {
-					do_warn(
-	_("would convert back to version 1,\n\tthis might destroy %d links\n"),
-						INT_GET(dinoc->di_nlink,
-							ARCH_CONVERT)
-						- XFS_MAXLINK_1);
-				}
-			}
-		} else  {
-			/*
-			 * do we have a v2 inode that we could convert back
-			 * to v1 without losing any links?  if we do and
-			 * we have a mismatch between superblock bits and the
-			 * version bit, alter the version bit in this case.
-			 *
-			 * the case where we lost links was handled above.
-			 */
-			do_warn(_("found version 2 inode %llu, "), lino);
-			if (!no_modify)  {
-				do_warn(_("converting back to version 1\n"));
-
-				dinoc->di_version =
-					XFS_DINODE_VERSION_1;
-				INT_SET(dinoc->di_onlink, ARCH_CONVERT,
-					INT_GET(dinoc->di_nlink, ARCH_CONVERT));
-
-				*dirty = 1;
-			} else  {
-				do_warn(_("would convert back to version 1\n"));
-			}
-		}
-	}
+	*dirty = process_check_inode_nlink_version(dinoc, lino);
 
-	/*
-	 * ok, if it's still a version 2 inode, it's going
-	 * to stay a version 2 inode.  it should have a zero
-	 * onlink field, so clear it.
-	 */
-	if (dinoc->di_version > XFS_DINODE_VERSION_1 &&
-	    INT_GET(dinoc->di_onlink, ARCH_CONVERT) > 0 &&
-	    fs_inode_nlink > 0)  {
-		if (!no_modify)  {
-			do_warn(
-_("clearing obsolete nlink field in version 2 inode %llu, was %d, now 0\n"),
-				lino, INT_GET(dinoc->di_onlink, ARCH_CONVERT));
-			dinoc->di_onlink = 0;
-			*dirty = 1;
-		} else  {
-			do_warn(
-_("would clear obsolete nlink field in version 2 inode %llu, currently %d\n"),
-				lino, INT_GET(dinoc->di_onlink, ARCH_CONVERT));
-			*dirty = 1;
-		}
-	}
+	return retval;
 
-	return(retval > 0 ? 1 : 0);
+clear_bad_out:
+	if (!no_modify)  {
+		*dirty += clear_dinode(mp, dino, lino);
+		ASSERT(*dirty > 0);
+	}
+bad_out:
+	*used = is_free;
+	*isa_dir = 0;
+	if (dblkmap)
+		blkmap_free(dblkmap);
+	return 1;
 }
 
 /*
@@ -2983,8 +2835,6 @@
  *				claimed blocks using the bitmap.
  *	Outs:
  *		dirty -- whether we changed the inode (1 == yes)
- *		cleared -- whether we cleared the inode (1 == yes).  In
- *				no modify mode, if we would have cleared it
  *		used -- 1 if the inode is used, 0 if free.  In no modify
  *			mode, whether the inode should be used or free
  *		isa_dir -- 1 if the inode is a directory, 0 if not.  In
@@ -2994,30 +2844,29 @@
  */
 
 int
-process_dinode(xfs_mount_t *mp,
-		xfs_dinode_t *dino,
-		xfs_agnumber_t agno,
-		xfs_agino_t ino,
-		int was_free,
-		int *dirty,
-		int *cleared,
-		int *used,
-		int ino_discovery,
-		int check_dups,
-		int extra_attr_check,
-		int *isa_dir,
-		xfs_ino_t *parent)
+process_dinode(
+	xfs_mount_t	*mp,
+	xfs_dinode_t	*dino,
+	xfs_agnumber_t	agno,
+	xfs_agino_t	ino,
+	int		was_free,
+	int		*dirty,
+	int		*used,
+	int		ino_discovery,
+	int		check_dups,
+	int		extra_attr_check,
+	int		*isa_dir,
+	xfs_ino_t	*parent)
 {
-	const int verify_mode = 0;
-	const int uncertain = 0;
+	const int	verify_mode = 0;
+	const int	uncertain = 0;
 
 #ifdef XR_INODE_TRACE
 	fprintf(stderr, "processing inode %d/%d\n", agno, ino);
 #endif
-	return(process_dinode_int(mp, dino, agno, ino, was_free, dirty,
-				cleared, used, verify_mode, uncertain,
-				ino_discovery, check_dups, extra_attr_check,
-				isa_dir, parent));
+	return process_dinode_int(mp, dino, agno, ino, was_free, dirty, used,
+				verify_mode, uncertain, ino_discovery,
+				check_dups, extra_attr_check, isa_dir, parent);
 }
 
 /*
@@ -3027,25 +2876,24 @@
  * if the inode passes the cursory sanity check, 1 otherwise.
  */
 int
-verify_dinode(xfs_mount_t *mp,
-		xfs_dinode_t *dino,
-		xfs_agnumber_t agno,
-		xfs_agino_t ino)
-{
-	xfs_ino_t parent;
-	int cleared = 0;
-	int used = 0;
-	int dirty = 0;
-	int isa_dir = 0;
-	const int verify_mode = 1;
-	const int check_dups = 0;
-	const int ino_discovery = 0;
-	const int uncertain = 0;
-
-	return(process_dinode_int(mp, dino, agno, ino, 0, &dirty,
-				&cleared, &used, verify_mode,
-				uncertain, ino_discovery, check_dups,
-				0, &isa_dir, &parent));
+verify_dinode(
+	xfs_mount_t	*mp,
+	xfs_dinode_t	*dino,
+	xfs_agnumber_t	agno,
+	xfs_agino_t	ino)
+{
+	xfs_ino_t	parent;
+	int		used = 0;
+	int		dirty = 0;
+	int		isa_dir = 0;
+	const int	verify_mode = 1;
+	const int	check_dups = 0;
+	const int	ino_discovery = 0;
+	const int	uncertain = 0;
+
+	return process_dinode_int(mp, dino, agno, ino, 0, &dirty, &used,
+				verify_mode, uncertain, ino_discovery,
+				check_dups, 0, &isa_dir, &parent);
 }
 
 /*
@@ -3054,23 +2902,22 @@
  * returns 0 if the inode passes the cursory sanity check, 1 otherwise.
  */
 int
-verify_uncertain_dinode(xfs_mount_t *mp,
-		xfs_dinode_t *dino,
-		xfs_agnumber_t agno,
-		xfs_agino_t ino)
-{
-	xfs_ino_t parent;
-	int cleared = 0;
-	int used = 0;
-	int dirty = 0;
-	int isa_dir = 0;
-	const int verify_mode = 1;
-	const int check_dups = 0;
-	const int ino_discovery = 0;
-	const int uncertain = 1;
-
-	return(process_dinode_int(mp, dino, agno, ino, 0, &dirty,
-				&cleared, &used, verify_mode,
-				uncertain, ino_discovery, check_dups,
-				0, &isa_dir, &parent));
+verify_uncertain_dinode(
+	xfs_mount_t	*mp,
+	xfs_dinode_t	*dino,
+	xfs_agnumber_t	agno,
+	xfs_agino_t	ino)
+{
+	xfs_ino_t	parent;
+	int		used = 0;
+	int		dirty = 0;
+	int		isa_dir = 0;
+	const int	verify_mode = 1;
+	const int	check_dups = 0;
+	const int	ino_discovery = 0;
+	const int	uncertain = 1;
+
+	return process_dinode_int(mp, dino, agno, ino, 0, &dirty, &used,
+				verify_mode, uncertain, ino_discovery,
+				check_dups, 0, &isa_dir, &parent);
 }
Index: ci/xfsprogs/repair/dinode.h
===================================================================
--- ci.orig/xfsprogs/repair/dinode.h	2007-11-16 14:45:56.000000000 +1100
+++ ci/xfsprogs/repair/dinode.h	2007-11-16 14:46:32.000000000 +1100
@@ -84,7 +84,6 @@
 		xfs_agino_t ino,
 		int was_free,
 		int *dirty,
-		int *tossit,
 		int *used,
 		int check_dirs,
 		int check_dups,

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: ci_user.patch --]
[-- Type: text/x-patch; name=ci_user.patch, Size: 155010 bytes --]


===========================================================================
xfsprogs/include/casefoldtable.h
===========================================================================

Index: ci/xfsprogs/include/casefoldtable.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ci/xfsprogs/include/casefoldtable.h	2008-01-18 15:00:08.788602304 +1100
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2007 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 CASEFOLDTABLE_H
+#define CASEFOLDTABLE_H
+
+#include "xfs_unicode.h"
+
+#define XFS_CFT_MIN_NUM_TABLES	3		/* minumum number of tables */
+#define XFS_CFT_MAX_NUM_TABLES	3		/* maximum number of tables */
+
+int libxfs_create_casefoldtable(xfs_mount_t *mp, int isturkic);
+
+#endif /* CASEFOLDTABLE_H */
Index: ci/xfsprogs/include/xfs_sb.h
===================================================================
--- ci.orig/xfsprogs/include/xfs_sb.h	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/include/xfs_sb.h	2008-01-18 15:00:08.788602304 +1100
@@ -46,10 +46,12 @@
 #define XFS_SB_VERSION_SECTORBIT	0x0800
 #define	XFS_SB_VERSION_EXTFLGBIT	0x1000
 #define	XFS_SB_VERSION_DIRV2BIT		0x2000
+#define XFS_SB_VERSION_OLDCIBIT		0x4000
 #define	XFS_SB_VERSION_MOREBITSBIT	0x8000
 #define	XFS_SB_VERSION_OKSASHFBITS	\
 	(XFS_SB_VERSION_EXTFLGBIT | \
-	 XFS_SB_VERSION_DIRV2BIT)
+	 XFS_SB_VERSION_DIRV2BIT | \
+	 XFS_SB_VERSION_OLDCIBIT)
 #define	XFS_SB_VERSION_OKREALFBITS	\
 	(XFS_SB_VERSION_ATTRBIT | \
 	 XFS_SB_VERSION_NLINKBIT | \
@@ -82,13 +84,12 @@
 #define XFS_SB_VERSION2_DONOTUSEBIT2	0x00000004
 #define XFS_SB_VERSION2_ATTR2BIT	0x00000008	/* Inline attr rework */
 #define XFS_SB_VERSION2_PARENTBIT	0x00000010	/* Parent pointers */
-#define XFS_SB_VERSION2_SASHFBITS	0xff000000	/* Mask: features that
-							   require changing
-							   PROM and SASH */
+#define XFS_SB_VERSION2_UNICODEBIT	0x00000020	/* Unicode names */
 
 #define	XFS_SB_VERSION2_OKREALFBITS	\
-	(XFS_SB_VERSION2_ATTR2BIT |	\
-	 XFS_SB_VERSION2_LAZYSBCOUNTBIT)
+	(XFS_SB_VERSION2_LAZYSBCOUNTBIT	| \
+	 XFS_SB_VERSION2_ATTR2BIT | \
+	 XFS_SB_VERSION2_UNICODEBIT)
 #define	XFS_SB_VERSION2_OKSASHFBITS	\
 	(0)
 #define XFS_SB_VERSION2_OKREALBITS	\
@@ -151,6 +152,8 @@
 	__uint16_t	sb_logsectsize;	/* sector size for the log, bytes */
 	__uint32_t	sb_logsunit;	/* stripe unit size for the log */
 	__uint32_t	sb_features2;	/* additional feature bits */
+	__uint32_t	sb_bad_features2; /* unusable space */
+	xfs_ino_t	sb_cftino;	/* unicode case folding table inode */
 } xfs_sb_t;
 
 /*
@@ -169,7 +172,7 @@
 	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_FEATURES2, XFS_SBS_BAD_FEATURES2, XFS_SBS_CFTINO,
 	XFS_SBS_FIELDCOUNT
 } xfs_sb_field_t;
 
@@ -194,13 +197,15 @@
 #define XFS_SB_IFREE		XFS_SB_MVAL(IFREE)
 #define XFS_SB_FDBLOCKS		XFS_SB_MVAL(FDBLOCKS)
 #define XFS_SB_FEATURES2	XFS_SB_MVAL(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		\
 	(XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
 	 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_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
+	 XFS_SB_CFTINO)
 
 
 /*
@@ -415,6 +420,12 @@
 		((sbp)->sb_versionnum & XFS_SB_VERSION_SECTORBIT);
 }
 
+static inline int xfs_sb_version_hasoldci(xfs_sb_t *sbp)
+{
+	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+		((sbp)->sb_versionnum & XFS_SB_VERSION_OLDCIBIT);
+}
+
 #define XFS_SB_VERSION_HASMOREBITS(sbp)	xfs_sb_version_hasmorebits(sbp)
 static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
 {
@@ -455,6 +466,12 @@
 		((sbp)->sb_features2 | XFS_SB_VERSION2_ATTR2BIT)));
 }
 
+static inline int xfs_sb_version_hasunicode(xfs_sb_t *sbp)
+{
+	return (xfs_sb_version_hasmorebits(sbp) &&	\
+		((sbp)->sb_features2 & XFS_SB_VERSION2_UNICODEBIT));
+}
+
 /*
  * end of superblock version macros
  */
Index: ci/xfsprogs/libxfs/Makefile
===================================================================
--- ci.orig/xfsprogs/libxfs/Makefile	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/libxfs/Makefile	2008-01-18 15:00:08.816598712 +1100
@@ -11,13 +11,13 @@
 LT_AGE = 0
 
 HFILES = xfs.h init.h
-CFILES = bit.c cache.c init.c logitem.c rdwr.c trans.c util.c \
-	xfs_alloc.c xfs_ialloc.c xfs_rtalloc.c \
+CFILES = bit.c cache.c casefoldtable.c init.c logitem.c rdwr.c trans.c util.c \
+	utf8.c xfs_alloc.c xfs_ialloc.c xfs_rtalloc.c \
 	xfs_inode.c xfs_btree.c xfs_alloc_btree.c xfs_ialloc_btree.c \
 	xfs_bmap_btree.c xfs_da_btree.c xfs_dir.c xfs_dir_leaf.c \
 	xfs_dir2.c xfs_dir2_leaf.c xfs_attr_leaf.c xfs_dir2_block.c \
 	xfs_dir2_node.c xfs_dir2_data.c xfs_dir2_sf.c xfs_bmap.c \
-	xfs_mount.c xfs_trans.c xfs_attr.c
+	xfs_mount.c xfs_trans.c xfs_attr.c xfs_unicode.c
 
 CFILES += $(PKG_PLATFORM).c
 PCFILES = darwin.c freebsd.c irix.c linux.c
Index: ci/xfsprogs/libxfs/casefoldtable.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ci/xfsprogs/libxfs/casefoldtable.c	2008-01-18 15:00:08.832596659 +1100
@@ -0,0 +1,760 @@
+/*
+ * Unicode case folding table automatically generated from
+ * http://www.unicode.org/Public/UNIDATA/CaseFolding.txt
+ *
+ * Characters that map to 0xe000 to 0xe3fff are indexes to the double
+ * character sequence in xfs_case_fold_double_table. 0xe400 to 0xe7ff
+ * map to the triple sequences in xfs_case_fold_triple_table.
+ */
+
+#include <xfs/libxfs.h>
+#include <casefoldtable.h>
+
+__uint16_t xfs_case_fold_table[15 * 256] = {
+
+	/* Most-significant-byte index table */
+
+	0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0700, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0800, 0x0900,
+	0x0000, 0x0a00, 0x0000, 0x0000, 0x0b00, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0c00, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0d00, 0x0000, 0x0000, 0x0000, 0x0e00,
+
+	/* Characters U+0000 to U+00FF */
+
+	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+	0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+	0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+	0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+	0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+	0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+	0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+	0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+	0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+	0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+	0x0078, 0x0079, 0x007a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+	0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+	0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+	0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+	0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+	0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+	0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+	0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+	0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+	0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+	0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+	0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x03bc, 0x00b6, 0x00b7,
+	0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+	0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+	0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+	0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00d7,
+	0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0xe000,
+	0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+	0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+	0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+	0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff,
+
+	/* Characters U+0100 to U+01FF */
+
+	0x0101, 0x0101, 0x0103, 0x0103, 0x0105, 0x0105, 0x0107, 0x0107,
+	0x0109, 0x0109, 0x010b, 0x010b, 0x010d, 0x010d, 0x010f, 0x010f,
+	0x0111, 0x0111, 0x0113, 0x0113, 0x0115, 0x0115, 0x0117, 0x0117,
+	0x0119, 0x0119, 0x011b, 0x011b, 0x011d, 0x011d, 0x011f, 0x011f,
+	0x0121, 0x0121, 0x0123, 0x0123, 0x0125, 0x0125, 0x0127, 0x0127,
+	0x0129, 0x0129, 0x012b, 0x012b, 0x012d, 0x012d, 0x012f, 0x012f,
+	0xe001, 0x0131, 0x0133, 0x0133, 0x0135, 0x0135, 0x0137, 0x0137,
+	0x0138, 0x013a, 0x013a, 0x013c, 0x013c, 0x013e, 0x013e, 0x0140,
+	0x0140, 0x0142, 0x0142, 0x0144, 0x0144, 0x0146, 0x0146, 0x0148,
+	0x0148, 0xe002, 0x014b, 0x014b, 0x014d, 0x014d, 0x014f, 0x014f,
+	0x0151, 0x0151, 0x0153, 0x0153, 0x0155, 0x0155, 0x0157, 0x0157,
+	0x0159, 0x0159, 0x015b, 0x015b, 0x015d, 0x015d, 0x015f, 0x015f,
+	0x0161, 0x0161, 0x0163, 0x0163, 0x0165, 0x0165, 0x0167, 0x0167,
+	0x0169, 0x0169, 0x016b, 0x016b, 0x016d, 0x016d, 0x016f, 0x016f,
+	0x0171, 0x0171, 0x0173, 0x0173, 0x0175, 0x0175, 0x0177, 0x0177,
+	0x00ff, 0x017a, 0x017a, 0x017c, 0x017c, 0x017e, 0x017e, 0x0073,
+	0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
+	0x0188, 0x0256, 0x0257, 0x018c, 0x018c, 0x018d, 0x01dd, 0x0259,
+	0x025b, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
+	0x0199, 0x0199, 0x019a, 0x019b, 0x026f, 0x0272, 0x019e, 0x0275,
+	0x01a1, 0x01a1, 0x01a3, 0x01a3, 0x01a5, 0x01a5, 0x0280, 0x01a8,
+	0x01a8, 0x0283, 0x01aa, 0x01ab, 0x01ad, 0x01ad, 0x0288, 0x01b0,
+	0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b4, 0x01b6, 0x01b6, 0x0292,
+	0x01b9, 0x01b9, 0x01ba, 0x01bb, 0x01bd, 0x01bd, 0x01be, 0x01bf,
+	0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c6, 0x01c6, 0x01c6, 0x01c9,
+	0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01cc, 0x01ce, 0x01ce, 0x01d0,
+	0x01d0, 0x01d2, 0x01d2, 0x01d4, 0x01d4, 0x01d6, 0x01d6, 0x01d8,
+	0x01d8, 0x01da, 0x01da, 0x01dc, 0x01dc, 0x01dd, 0x01df, 0x01df,
+	0x01e1, 0x01e1, 0x01e3, 0x01e3, 0x01e5, 0x01e5, 0x01e7, 0x01e7,
+	0x01e9, 0x01e9, 0x01eb, 0x01eb, 0x01ed, 0x01ed, 0x01ef, 0x01ef,
+	0xe003, 0x01f3, 0x01f3, 0x01f3, 0x01f5, 0x01f5, 0x0195, 0x01bf,
+	0x01f9, 0x01f9, 0x01fb, 0x01fb, 0x01fd, 0x01fd, 0x01ff, 0x01ff,
+
+	/* Characters U+0200 to U+02FF */
+
+	0x0201, 0x0201, 0x0203, 0x0203, 0x0205, 0x0205, 0x0207, 0x0207,
+	0x0209, 0x0209, 0x020b, 0x020b, 0x020d, 0x020d, 0x020f, 0x020f,
+	0x0211, 0x0211, 0x0213, 0x0213, 0x0215, 0x0215, 0x0217, 0x0217,
+	0x0219, 0x0219, 0x021b, 0x021b, 0x021d, 0x021d, 0x021f, 0x021f,
+	0x019e, 0x0221, 0x0223, 0x0223, 0x0225, 0x0225, 0x0227, 0x0227,
+	0x0229, 0x0229, 0x022b, 0x022b, 0x022d, 0x022d, 0x022f, 0x022f,
+	0x0231, 0x0231, 0x0233, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237,
+	0x0238, 0x0239, 0x2c65, 0x023c, 0x023c, 0x019a, 0x2c66, 0x023f,
+	0x0240, 0x0242, 0x0242, 0x0180, 0x0289, 0x028c, 0x0247, 0x0247,
+	0x0249, 0x0249, 0x024b, 0x024b, 0x024d, 0x024d, 0x024f, 0x024f,
+	0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257,
+	0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f,
+	0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267,
+	0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f,
+	0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277,
+	0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f,
+	0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287,
+	0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f,
+	0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297,
+	0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f,
+	0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7,
+	0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af,
+	0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7,
+	0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf,
+	0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7,
+	0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf,
+	0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7,
+	0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df,
+	0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7,
+	0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef,
+	0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7,
+	0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff,
+
+	/* Characters U+0300 to U+03FF */
+
+	0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
+	0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f,
+	0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
+	0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f,
+	0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
+	0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f,
+	0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
+	0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f,
+	0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x03b9, 0x0346, 0x0347,
+	0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f,
+	0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
+	0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f,
+	0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
+	0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f,
+	0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377,
+	0x0378, 0x0379, 0x037a, 0x037b, 0x037c, 0x037d, 0x037e, 0x037f,
+	0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x03ac, 0x0387,
+	0x03ad, 0x03ae, 0x03af, 0x038b, 0x03cc, 0x038d, 0x03cd, 0x03ce,
+	0xe400, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
+	0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+	0x03c0, 0x03c1, 0x03a2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
+	0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03ac, 0x03ad, 0x03ae, 0x03af,
+	0xe401, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
+	0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+	0x03c0, 0x03c1, 0x03c3, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
+	0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x03cf,
+	0x03b2, 0x03b8, 0x03d2, 0x03d3, 0x03d4, 0x03c6, 0x03c0, 0x03d7,
+	0x03d9, 0x03d9, 0x03db, 0x03db, 0x03dd, 0x03dd, 0x03df, 0x03df,
+	0x03e1, 0x03e1, 0x03e3, 0x03e3, 0x03e5, 0x03e5, 0x03e7, 0x03e7,
+	0x03e9, 0x03e9, 0x03eb, 0x03eb, 0x03ed, 0x03ed, 0x03ef, 0x03ef,
+	0x03ba, 0x03c1, 0x03f2, 0x03f3, 0x03b8, 0x03b5, 0x03f6, 0x03f8,
+	0x03f8, 0x03f2, 0x03fb, 0x03fb, 0x03fc, 0x037b, 0x037c, 0x037d,
+
+	/* Characters U+0400 to U+04FF */
+
+	0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+	0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f,
+	0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+	0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+	0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+	0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+	0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+	0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+	0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+	0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+	0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+	0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f,
+	0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467,
+	0x0469, 0x0469, 0x046b, 0x046b, 0x046d, 0x046d, 0x046f, 0x046f,
+	0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0477, 0x0477,
+	0x0479, 0x0479, 0x047b, 0x047b, 0x047d, 0x047d, 0x047f, 0x047f,
+	0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
+	0x0488, 0x0489, 0x048b, 0x048b, 0x048d, 0x048d, 0x048f, 0x048f,
+	0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497,
+	0x0499, 0x0499, 0x049b, 0x049b, 0x049d, 0x049d, 0x049f, 0x049f,
+	0x04a1, 0x04a1, 0x04a3, 0x04a3, 0x04a5, 0x04a5, 0x04a7, 0x04a7,
+	0x04a9, 0x04a9, 0x04ab, 0x04ab, 0x04ad, 0x04ad, 0x04af, 0x04af,
+	0x04b1, 0x04b1, 0x04b3, 0x04b3, 0x04b5, 0x04b5, 0x04b7, 0x04b7,
+	0x04b9, 0x04b9, 0x04bb, 0x04bb, 0x04bd, 0x04bd, 0x04bf, 0x04bf,
+	0x04cf, 0x04c2, 0x04c2, 0x04c4, 0x04c4, 0x04c6, 0x04c6, 0x04c8,
+	0x04c8, 0x04ca, 0x04ca, 0x04cc, 0x04cc, 0x04ce, 0x04ce, 0x04cf,
+	0x04d1, 0x04d1, 0x04d3, 0x04d3, 0x04d5, 0x04d5, 0x04d7, 0x04d7,
+	0x04d9, 0x04d9, 0x04db, 0x04db, 0x04dd, 0x04dd, 0x04df, 0x04df,
+	0x04e1, 0x04e1, 0x04e3, 0x04e3, 0x04e5, 0x04e5, 0x04e7, 0x04e7,
+	0x04e9, 0x04e9, 0x04eb, 0x04eb, 0x04ed, 0x04ed, 0x04ef, 0x04ef,
+	0x04f1, 0x04f1, 0x04f3, 0x04f3, 0x04f5, 0x04f5, 0x04f7, 0x04f7,
+	0x04f9, 0x04f9, 0x04fb, 0x04fb, 0x04fd, 0x04fd, 0x04ff, 0x04ff,
+
+	/* Characters U+0500 to U+05FF */
+
+	0x0501, 0x0501, 0x0503, 0x0503, 0x0505, 0x0505, 0x0507, 0x0507,
+	0x0509, 0x0509, 0x050b, 0x050b, 0x050d, 0x050d, 0x050f, 0x050f,
+	0x0511, 0x0511, 0x0513, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517,
+	0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f,
+	0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527,
+	0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f,
+	0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+	0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f,
+	0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+	0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f,
+	0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557,
+	0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f,
+	0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+	0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f,
+	0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+	0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f,
+	0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0xe004,
+	0x0588, 0x0589, 0x058a, 0x058b, 0x058c, 0x058d, 0x058e, 0x058f,
+	0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597,
+	0x0598, 0x0599, 0x059a, 0x059b, 0x059c, 0x059d, 0x059e, 0x059f,
+	0x05a0, 0x05a1, 0x05a2, 0x05a3, 0x05a4, 0x05a5, 0x05a6, 0x05a7,
+	0x05a8, 0x05a9, 0x05aa, 0x05ab, 0x05ac, 0x05ad, 0x05ae, 0x05af,
+	0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7,
+	0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf,
+	0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05c4, 0x05c5, 0x05c6, 0x05c7,
+	0x05c8, 0x05c9, 0x05ca, 0x05cb, 0x05cc, 0x05cd, 0x05ce, 0x05cf,
+	0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
+	0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
+	0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
+	0x05e8, 0x05e9, 0x05ea, 0x05eb, 0x05ec, 0x05ed, 0x05ee, 0x05ef,
+	0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0x05f5, 0x05f6, 0x05f7,
+	0x05f8, 0x05f9, 0x05fa, 0x05fb, 0x05fc, 0x05fd, 0x05fe, 0x05ff,
+
+	/* Characters U+1000 to U+10FF */
+
+	0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
+	0x1008, 0x1009, 0x100a, 0x100b, 0x100c, 0x100d, 0x100e, 0x100f,
+	0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017,
+	0x1018, 0x1019, 0x101a, 0x101b, 0x101c, 0x101d, 0x101e, 0x101f,
+	0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027,
+	0x1028, 0x1029, 0x102a, 0x102b, 0x102c, 0x102d, 0x102e, 0x102f,
+	0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037,
+	0x1038, 0x1039, 0x103a, 0x103b, 0x103c, 0x103d, 0x103e, 0x103f,
+	0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047,
+	0x1048, 0x1049, 0x104a, 0x104b, 0x104c, 0x104d, 0x104e, 0x104f,
+	0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057,
+	0x1058, 0x1059, 0x105a, 0x105b, 0x105c, 0x105d, 0x105e, 0x105f,
+	0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067,
+	0x1068, 0x1069, 0x106a, 0x106b, 0x106c, 0x106d, 0x106e, 0x106f,
+	0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077,
+	0x1078, 0x1079, 0x107a, 0x107b, 0x107c, 0x107d, 0x107e, 0x107f,
+	0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087,
+	0x1088, 0x1089, 0x108a, 0x108b, 0x108c, 0x108d, 0x108e, 0x108f,
+	0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097,
+	0x1098, 0x1099, 0x109a, 0x109b, 0x109c, 0x109d, 0x109e, 0x109f,
+	0x2d00, 0x2d01, 0x2d02, 0x2d03, 0x2d04, 0x2d05, 0x2d06, 0x2d07,
+	0x2d08, 0x2d09, 0x2d0a, 0x2d0b, 0x2d0c, 0x2d0d, 0x2d0e, 0x2d0f,
+	0x2d10, 0x2d11, 0x2d12, 0x2d13, 0x2d14, 0x2d15, 0x2d16, 0x2d17,
+	0x2d18, 0x2d19, 0x2d1a, 0x2d1b, 0x2d1c, 0x2d1d, 0x2d1e, 0x2d1f,
+	0x2d20, 0x2d21, 0x2d22, 0x2d23, 0x2d24, 0x2d25, 0x10c6, 0x10c7,
+	0x10c8, 0x10c9, 0x10ca, 0x10cb, 0x10cc, 0x10cd, 0x10ce, 0x10cf,
+	0x10d0, 0x10d1, 0x10d2, 0x10d3, 0x10d4, 0x10d5, 0x10d6, 0x10d7,
+	0x10d8, 0x10d9, 0x10da, 0x10db, 0x10dc, 0x10dd, 0x10de, 0x10df,
+	0x10e0, 0x10e1, 0x10e2, 0x10e3, 0x10e4, 0x10e5, 0x10e6, 0x10e7,
+	0x10e8, 0x10e9, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x10ee, 0x10ef,
+	0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7,
+	0x10f8, 0x10f9, 0x10fa, 0x10fb, 0x10fc, 0x10fd, 0x10fe, 0x10ff,
+
+	/* Characters U+1E00 to U+1EFF */
+
+	0x1e01, 0x1e01, 0x1e03, 0x1e03, 0x1e05, 0x1e05, 0x1e07, 0x1e07,
+	0x1e09, 0x1e09, 0x1e0b, 0x1e0b, 0x1e0d, 0x1e0d, 0x1e0f, 0x1e0f,
+	0x1e11, 0x1e11, 0x1e13, 0x1e13, 0x1e15, 0x1e15, 0x1e17, 0x1e17,
+	0x1e19, 0x1e19, 0x1e1b, 0x1e1b, 0x1e1d, 0x1e1d, 0x1e1f, 0x1e1f,
+	0x1e21, 0x1e21, 0x1e23, 0x1e23, 0x1e25, 0x1e25, 0x1e27, 0x1e27,
+	0x1e29, 0x1e29, 0x1e2b, 0x1e2b, 0x1e2d, 0x1e2d, 0x1e2f, 0x1e2f,
+	0x1e31, 0x1e31, 0x1e33, 0x1e33, 0x1e35, 0x1e35, 0x1e37, 0x1e37,
+	0x1e39, 0x1e39, 0x1e3b, 0x1e3b, 0x1e3d, 0x1e3d, 0x1e3f, 0x1e3f,
+	0x1e41, 0x1e41, 0x1e43, 0x1e43, 0x1e45, 0x1e45, 0x1e47, 0x1e47,
+	0x1e49, 0x1e49, 0x1e4b, 0x1e4b, 0x1e4d, 0x1e4d, 0x1e4f, 0x1e4f,
+	0x1e51, 0x1e51, 0x1e53, 0x1e53, 0x1e55, 0x1e55, 0x1e57, 0x1e57,
+	0x1e59, 0x1e59, 0x1e5b, 0x1e5b, 0x1e5d, 0x1e5d, 0x1e5f, 0x1e5f,
+	0x1e61, 0x1e61, 0x1e63, 0x1e63, 0x1e65, 0x1e65, 0x1e67, 0x1e67,
+	0x1e69, 0x1e69, 0x1e6b, 0x1e6b, 0x1e6d, 0x1e6d, 0x1e6f, 0x1e6f,
+	0x1e71, 0x1e71, 0x1e73, 0x1e73, 0x1e75, 0x1e75, 0x1e77, 0x1e77,
+	0x1e79, 0x1e79, 0x1e7b, 0x1e7b, 0x1e7d, 0x1e7d, 0x1e7f, 0x1e7f,
+	0x1e81, 0x1e81, 0x1e83, 0x1e83, 0x1e85, 0x1e85, 0x1e87, 0x1e87,
+	0x1e89, 0x1e89, 0x1e8b, 0x1e8b, 0x1e8d, 0x1e8d, 0x1e8f, 0x1e8f,
+	0x1e91, 0x1e91, 0x1e93, 0x1e93, 0x1e95, 0x1e95, 0xe005, 0xe006,
+	0xe007, 0xe008, 0xe009, 0x1e61, 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f,
+	0x1ea1, 0x1ea1, 0x1ea3, 0x1ea3, 0x1ea5, 0x1ea5, 0x1ea7, 0x1ea7,
+	0x1ea9, 0x1ea9, 0x1eab, 0x1eab, 0x1ead, 0x1ead, 0x1eaf, 0x1eaf,
+	0x1eb1, 0x1eb1, 0x1eb3, 0x1eb3, 0x1eb5, 0x1eb5, 0x1eb7, 0x1eb7,
+	0x1eb9, 0x1eb9, 0x1ebb, 0x1ebb, 0x1ebd, 0x1ebd, 0x1ebf, 0x1ebf,
+	0x1ec1, 0x1ec1, 0x1ec3, 0x1ec3, 0x1ec5, 0x1ec5, 0x1ec7, 0x1ec7,
+	0x1ec9, 0x1ec9, 0x1ecb, 0x1ecb, 0x1ecd, 0x1ecd, 0x1ecf, 0x1ecf,
+	0x1ed1, 0x1ed1, 0x1ed3, 0x1ed3, 0x1ed5, 0x1ed5, 0x1ed7, 0x1ed7,
+	0x1ed9, 0x1ed9, 0x1edb, 0x1edb, 0x1edd, 0x1edd, 0x1edf, 0x1edf,
+	0x1ee1, 0x1ee1, 0x1ee3, 0x1ee3, 0x1ee5, 0x1ee5, 0x1ee7, 0x1ee7,
+	0x1ee9, 0x1ee9, 0x1eeb, 0x1eeb, 0x1eed, 0x1eed, 0x1eef, 0x1eef,
+	0x1ef1, 0x1ef1, 0x1ef3, 0x1ef3, 0x1ef5, 0x1ef5, 0x1ef7, 0x1ef7,
+	0x1ef9, 0x1ef9, 0x1efa, 0x1efb, 0x1efc, 0x1efd, 0x1efe, 0x1eff,
+
+	/* Characters U+1F00 to U+1FFF */
+
+	0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07,
+	0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07,
+	0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f16, 0x1f17,
+	0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f1e, 0x1f1f,
+	0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27,
+	0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27,
+	0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37,
+	0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37,
+	0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f46, 0x1f47,
+	0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f4e, 0x1f4f,
+	0xe00a, 0x1f51, 0xe402, 0x1f53, 0xe403, 0x1f55, 0xe404, 0x1f57,
+	0x1f58, 0x1f51, 0x1f5a, 0x1f53, 0x1f5c, 0x1f55, 0x1f5e, 0x1f57,
+	0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67,
+	0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67,
+	0x1f70, 0x1f71, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1f76, 0x1f77,
+	0x1f78, 0x1f79, 0x1f7a, 0x1f7b, 0x1f7c, 0x1f7d, 0x1f7e, 0x1f7f,
+	0xe00b, 0xe00c, 0xe00d, 0xe00e, 0xe00f, 0xe010, 0xe011, 0xe012,
+	0xe013, 0xe014, 0xe015, 0xe016, 0xe017, 0xe018, 0xe019, 0xe01a,
+	0xe01b, 0xe01c, 0xe01d, 0xe01e, 0xe01f, 0xe020, 0xe021, 0xe022,
+	0xe023, 0xe024, 0xe025, 0xe026, 0xe027, 0xe028, 0xe029, 0xe02a,
+	0xe02b, 0xe02c, 0xe02d, 0xe02e, 0xe02f, 0xe030, 0xe031, 0xe032,
+	0xe033, 0xe034, 0xe035, 0xe036, 0xe037, 0xe038, 0xe039, 0xe03a,
+	0x1fb0, 0x1fb1, 0xe03b, 0xe03c, 0xe03d, 0x1fb5, 0xe03e, 0xe405,
+	0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0xe03f, 0x1fbd, 0x03b9, 0x1fbf,
+	0x1fc0, 0x1fc1, 0xe040, 0xe041, 0xe042, 0x1fc5, 0xe043, 0xe406,
+	0x1f72, 0x1f73, 0x1f74, 0x1f75, 0xe044, 0x1fcd, 0x1fce, 0x1fcf,
+	0x1fd0, 0x1fd1, 0xe407, 0xe408, 0x1fd4, 0x1fd5, 0xe045, 0xe409,
+	0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf,
+	0x1fe0, 0x1fe1, 0xe40a, 0xe40b, 0xe046, 0x1fe5, 0xe047, 0xe40c,
+	0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1fed, 0x1fee, 0x1fef,
+	0x1ff0, 0x1ff1, 0xe048, 0xe049, 0xe04a, 0x1ff5, 0xe04b, 0xe40d,
+	0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0xe04c, 0x1ffd, 0x1ffe, 0x1fff,
+
+	/* Characters U+2100 to U+21FF */
+
+	0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107,
+	0x2108, 0x2109, 0x210a, 0x210b, 0x210c, 0x210d, 0x210e, 0x210f,
+	0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117,
+	0x2118, 0x2119, 0x211a, 0x211b, 0x211c, 0x211d, 0x211e, 0x211f,
+	0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x03c9, 0x2127,
+	0x2128, 0x2129, 0x006b, 0x00e5, 0x212c, 0x212d, 0x212e, 0x212f,
+	0x2130, 0x2131, 0x214e, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137,
+	0x2138, 0x2139, 0x213a, 0x213b, 0x213c, 0x213d, 0x213e, 0x213f,
+	0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147,
+	0x2148, 0x2149, 0x214a, 0x214b, 0x214c, 0x214d, 0x214e, 0x214f,
+	0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157,
+	0x2158, 0x2159, 0x215a, 0x215b, 0x215c, 0x215d, 0x215e, 0x215f,
+	0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+	0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f,
+	0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+	0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f,
+	0x2180, 0x2181, 0x2182, 0x2184, 0x2184, 0x2185, 0x2186, 0x2187,
+	0x2188, 0x2189, 0x218a, 0x218b, 0x218c, 0x218d, 0x218e, 0x218f,
+	0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197,
+	0x2198, 0x2199, 0x219a, 0x219b, 0x219c, 0x219d, 0x219e, 0x219f,
+	0x21a0, 0x21a1, 0x21a2, 0x21a3, 0x21a4, 0x21a5, 0x21a6, 0x21a7,
+	0x21a8, 0x21a9, 0x21aa, 0x21ab, 0x21ac, 0x21ad, 0x21ae, 0x21af,
+	0x21b0, 0x21b1, 0x21b2, 0x21b3, 0x21b4, 0x21b5, 0x21b6, 0x21b7,
+	0x21b8, 0x21b9, 0x21ba, 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf,
+	0x21c0, 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7,
+	0x21c8, 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf,
+	0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x21d5, 0x21d6, 0x21d7,
+	0x21d8, 0x21d9, 0x21da, 0x21db, 0x21dc, 0x21dd, 0x21de, 0x21df,
+	0x21e0, 0x21e1, 0x21e2, 0x21e3, 0x21e4, 0x21e5, 0x21e6, 0x21e7,
+	0x21e8, 0x21e9, 0x21ea, 0x21eb, 0x21ec, 0x21ed, 0x21ee, 0x21ef,
+	0x21f0, 0x21f1, 0x21f2, 0x21f3, 0x21f4, 0x21f5, 0x21f6, 0x21f7,
+	0x21f8, 0x21f9, 0x21fa, 0x21fb, 0x21fc, 0x21fd, 0x21fe, 0x21ff,
+
+	/* Characters U+2400 to U+24FF */
+
+	0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407,
+	0x2408, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x240e, 0x240f,
+	0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417,
+	0x2418, 0x2419, 0x241a, 0x241b, 0x241c, 0x241d, 0x241e, 0x241f,
+	0x2420, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427,
+	0x2428, 0x2429, 0x242a, 0x242b, 0x242c, 0x242d, 0x242e, 0x242f,
+	0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437,
+	0x2438, 0x2439, 0x243a, 0x243b, 0x243c, 0x243d, 0x243e, 0x243f,
+	0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447,
+	0x2448, 0x2449, 0x244a, 0x244b, 0x244c, 0x244d, 0x244e, 0x244f,
+	0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457,
+	0x2458, 0x2459, 0x245a, 0x245b, 0x245c, 0x245d, 0x245e, 0x245f,
+	0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467,
+	0x2468, 0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f,
+	0x2470, 0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0x2477,
+	0x2478, 0x2479, 0x247a, 0x247b, 0x247c, 0x247d, 0x247e, 0x247f,
+	0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487,
+	0x2488, 0x2489, 0x248a, 0x248b, 0x248c, 0x248d, 0x248e, 0x248f,
+	0x2490, 0x2491, 0x2492, 0x2493, 0x2494, 0x2495, 0x2496, 0x2497,
+	0x2498, 0x2499, 0x249a, 0x249b, 0x249c, 0x249d, 0x249e, 0x249f,
+	0x24a0, 0x24a1, 0x24a2, 0x24a3, 0x24a4, 0x24a5, 0x24a6, 0x24a7,
+	0x24a8, 0x24a9, 0x24aa, 0x24ab, 0x24ac, 0x24ad, 0x24ae, 0x24af,
+	0x24b0, 0x24b1, 0x24b2, 0x24b3, 0x24b4, 0x24b5, 0x24d0, 0x24d1,
+	0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9,
+	0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1,
+	0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9,
+	0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7,
+	0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df,
+	0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7,
+	0x24e8, 0x24e9, 0x24ea, 0x24eb, 0x24ec, 0x24ed, 0x24ee, 0x24ef,
+	0x24f0, 0x24f1, 0x24f2, 0x24f3, 0x24f4, 0x24f5, 0x24f6, 0x24f7,
+	0x24f8, 0x24f9, 0x24fa, 0x24fb, 0x24fc, 0x24fd, 0x24fe, 0x24ff,
+
+	/* Characters U+2C00 to U+2CFF */
+
+	0x2c30, 0x2c31, 0x2c32, 0x2c33, 0x2c34, 0x2c35, 0x2c36, 0x2c37,
+	0x2c38, 0x2c39, 0x2c3a, 0x2c3b, 0x2c3c, 0x2c3d, 0x2c3e, 0x2c3f,
+	0x2c40, 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47,
+	0x2c48, 0x2c49, 0x2c4a, 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f,
+	0x2c50, 0x2c51, 0x2c52, 0x2c53, 0x2c54, 0x2c55, 0x2c56, 0x2c57,
+	0x2c58, 0x2c59, 0x2c5a, 0x2c5b, 0x2c5c, 0x2c5d, 0x2c5e, 0x2c2f,
+	0x2c30, 0x2c31, 0x2c32, 0x2c33, 0x2c34, 0x2c35, 0x2c36, 0x2c37,
+	0x2c38, 0x2c39, 0x2c3a, 0x2c3b, 0x2c3c, 0x2c3d, 0x2c3e, 0x2c3f,
+	0x2c40, 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47,
+	0x2c48, 0x2c49, 0x2c4a, 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f,
+	0x2c50, 0x2c51, 0x2c52, 0x2c53, 0x2c54, 0x2c55, 0x2c56, 0x2c57,
+	0x2c58, 0x2c59, 0x2c5a, 0x2c5b, 0x2c5c, 0x2c5d, 0x2c5e, 0x2c5f,
+	0x2c61, 0x2c61, 0x026b, 0x1d7d, 0x027d, 0x2c65, 0x2c66, 0x2c68,
+	0x2c68, 0x2c6a, 0x2c6a, 0x2c6c, 0x2c6c, 0x2c6d, 0x2c6e, 0x2c6f,
+	0x2c70, 0x2c71, 0x2c72, 0x2c73, 0x2c74, 0x2c76, 0x2c76, 0x2c77,
+	0x2c78, 0x2c79, 0x2c7a, 0x2c7b, 0x2c7c, 0x2c7d, 0x2c7e, 0x2c7f,
+	0x2c81, 0x2c81, 0x2c83, 0x2c83, 0x2c85, 0x2c85, 0x2c87, 0x2c87,
+	0x2c89, 0x2c89, 0x2c8b, 0x2c8b, 0x2c8d, 0x2c8d, 0x2c8f, 0x2c8f,
+	0x2c91, 0x2c91, 0x2c93, 0x2c93, 0x2c95, 0x2c95, 0x2c97, 0x2c97,
+	0x2c99, 0x2c99, 0x2c9b, 0x2c9b, 0x2c9d, 0x2c9d, 0x2c9f, 0x2c9f,
+	0x2ca1, 0x2ca1, 0x2ca3, 0x2ca3, 0x2ca5, 0x2ca5, 0x2ca7, 0x2ca7,
+	0x2ca9, 0x2ca9, 0x2cab, 0x2cab, 0x2cad, 0x2cad, 0x2caf, 0x2caf,
+	0x2cb1, 0x2cb1, 0x2cb3, 0x2cb3, 0x2cb5, 0x2cb5, 0x2cb7, 0x2cb7,
+	0x2cb9, 0x2cb9, 0x2cbb, 0x2cbb, 0x2cbd, 0x2cbd, 0x2cbf, 0x2cbf,
+	0x2cc1, 0x2cc1, 0x2cc3, 0x2cc3, 0x2cc5, 0x2cc5, 0x2cc7, 0x2cc7,
+	0x2cc9, 0x2cc9, 0x2ccb, 0x2ccb, 0x2ccd, 0x2ccd, 0x2ccf, 0x2ccf,
+	0x2cd1, 0x2cd1, 0x2cd3, 0x2cd3, 0x2cd5, 0x2cd5, 0x2cd7, 0x2cd7,
+	0x2cd9, 0x2cd9, 0x2cdb, 0x2cdb, 0x2cdd, 0x2cdd, 0x2cdf, 0x2cdf,
+	0x2ce1, 0x2ce1, 0x2ce3, 0x2ce3, 0x2ce4, 0x2ce5, 0x2ce6, 0x2ce7,
+	0x2ce8, 0x2ce9, 0x2cea, 0x2ceb, 0x2cec, 0x2ced, 0x2cee, 0x2cef,
+	0x2cf0, 0x2cf1, 0x2cf2, 0x2cf3, 0x2cf4, 0x2cf5, 0x2cf6, 0x2cf7,
+	0x2cf8, 0x2cf9, 0x2cfa, 0x2cfb, 0x2cfc, 0x2cfd, 0x2cfe, 0x2cff,
+
+	/* Characters U+FB00 to U+FBFF */
+
+	0xe04d, 0xe04e, 0xe04f, 0xe40e, 0xe40f, 0xe050, 0xe051, 0xfb07,
+	0xfb08, 0xfb09, 0xfb0a, 0xfb0b, 0xfb0c, 0xfb0d, 0xfb0e, 0xfb0f,
+	0xfb10, 0xfb11, 0xfb12, 0xe052, 0xe053, 0xe054, 0xe055, 0xe056,
+	0xfb18, 0xfb19, 0xfb1a, 0xfb1b, 0xfb1c, 0xfb1d, 0xfb1e, 0xfb1f,
+	0xfb20, 0xfb21, 0xfb22, 0xfb23, 0xfb24, 0xfb25, 0xfb26, 0xfb27,
+	0xfb28, 0xfb29, 0xfb2a, 0xfb2b, 0xfb2c, 0xfb2d, 0xfb2e, 0xfb2f,
+	0xfb30, 0xfb31, 0xfb32, 0xfb33, 0xfb34, 0xfb35, 0xfb36, 0xfb37,
+	0xfb38, 0xfb39, 0xfb3a, 0xfb3b, 0xfb3c, 0xfb3d, 0xfb3e, 0xfb3f,
+	0xfb40, 0xfb41, 0xfb42, 0xfb43, 0xfb44, 0xfb45, 0xfb46, 0xfb47,
+	0xfb48, 0xfb49, 0xfb4a, 0xfb4b, 0xfb4c, 0xfb4d, 0xfb4e, 0xfb4f,
+	0xfb50, 0xfb51, 0xfb52, 0xfb53, 0xfb54, 0xfb55, 0xfb56, 0xfb57,
+	0xfb58, 0xfb59, 0xfb5a, 0xfb5b, 0xfb5c, 0xfb5d, 0xfb5e, 0xfb5f,
+	0xfb60, 0xfb61, 0xfb62, 0xfb63, 0xfb64, 0xfb65, 0xfb66, 0xfb67,
+	0xfb68, 0xfb69, 0xfb6a, 0xfb6b, 0xfb6c, 0xfb6d, 0xfb6e, 0xfb6f,
+	0xfb70, 0xfb71, 0xfb72, 0xfb73, 0xfb74, 0xfb75, 0xfb76, 0xfb77,
+	0xfb78, 0xfb79, 0xfb7a, 0xfb7b, 0xfb7c, 0xfb7d, 0xfb7e, 0xfb7f,
+	0xfb80, 0xfb81, 0xfb82, 0xfb83, 0xfb84, 0xfb85, 0xfb86, 0xfb87,
+	0xfb88, 0xfb89, 0xfb8a, 0xfb8b, 0xfb8c, 0xfb8d, 0xfb8e, 0xfb8f,
+	0xfb90, 0xfb91, 0xfb92, 0xfb93, 0xfb94, 0xfb95, 0xfb96, 0xfb97,
+	0xfb98, 0xfb99, 0xfb9a, 0xfb9b, 0xfb9c, 0xfb9d, 0xfb9e, 0xfb9f,
+	0xfba0, 0xfba1, 0xfba2, 0xfba3, 0xfba4, 0xfba5, 0xfba6, 0xfba7,
+	0xfba8, 0xfba9, 0xfbaa, 0xfbab, 0xfbac, 0xfbad, 0xfbae, 0xfbaf,
+	0xfbb0, 0xfbb1, 0xfbb2, 0xfbb3, 0xfbb4, 0xfbb5, 0xfbb6, 0xfbb7,
+	0xfbb8, 0xfbb9, 0xfbba, 0xfbbb, 0xfbbc, 0xfbbd, 0xfbbe, 0xfbbf,
+	0xfbc0, 0xfbc1, 0xfbc2, 0xfbc3, 0xfbc4, 0xfbc5, 0xfbc6, 0xfbc7,
+	0xfbc8, 0xfbc9, 0xfbca, 0xfbcb, 0xfbcc, 0xfbcd, 0xfbce, 0xfbcf,
+	0xfbd0, 0xfbd1, 0xfbd2, 0xfbd3, 0xfbd4, 0xfbd5, 0xfbd6, 0xfbd7,
+	0xfbd8, 0xfbd9, 0xfbda, 0xfbdb, 0xfbdc, 0xfbdd, 0xfbde, 0xfbdf,
+	0xfbe0, 0xfbe1, 0xfbe2, 0xfbe3, 0xfbe4, 0xfbe5, 0xfbe6, 0xfbe7,
+	0xfbe8, 0xfbe9, 0xfbea, 0xfbeb, 0xfbec, 0xfbed, 0xfbee, 0xfbef,
+	0xfbf0, 0xfbf1, 0xfbf2, 0xfbf3, 0xfbf4, 0xfbf5, 0xfbf6, 0xfbf7,
+	0xfbf8, 0xfbf9, 0xfbfa, 0xfbfb, 0xfbfc, 0xfbfd, 0xfbfe, 0xfbff,
+
+	/* Characters U+FF00 to U+FFFF */
+
+	0xff00, 0xff01, 0xff02, 0xff03, 0xff04, 0xff05, 0xff06, 0xff07,
+	0xff08, 0xff09, 0xff0a, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f,
+	0xff10, 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17,
+	0xff18, 0xff19, 0xff1a, 0xff1b, 0xff1c, 0xff1d, 0xff1e, 0xff1f,
+	0xff20, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47,
+	0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f,
+	0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57,
+	0xff58, 0xff59, 0xff5a, 0xff3b, 0xff3c, 0xff3d, 0xff3e, 0xff3f,
+	0xff40, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47,
+	0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f,
+	0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57,
+	0xff58, 0xff59, 0xff5a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f,
+	0xff60, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67,
+	0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f,
+	0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77,
+	0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f,
+	0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87,
+	0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f,
+	0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97,
+	0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f,
+	0xffa0, 0xffa1, 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7,
+	0xffa8, 0xffa9, 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf,
+	0xffb0, 0xffb1, 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7,
+	0xffb8, 0xffb9, 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf,
+	0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7,
+	0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf,
+	0xffd0, 0xffd1, 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7,
+	0xffd8, 0xffd9, 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf,
+	0xffe0, 0xffe1, 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7,
+	0xffe8, 0xffe9, 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef,
+	0xfff0, 0xfff1, 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7,
+	0xfff8, 0xfff9, 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff,
+};
+
+__uint16_t xfs_case_fold_double_table[87][2] = {
+	/* U+00DF */ {0x0073, 0x0073}, /* U+0130 */ {0x0069, 0x0307},
+	/* U+0149 */ {0x02bc, 0x006e}, /* U+01F0 */ {0x006a, 0x030c},
+	/* U+0587 */ {0x0565, 0x0582}, /* U+1E96 */ {0x0068, 0x0331},
+	/* U+1E97 */ {0x0074, 0x0308}, /* U+1E98 */ {0x0077, 0x030a},
+	/* U+1E99 */ {0x0079, 0x030a}, /* U+1E9A */ {0x0061, 0x02be},
+	/* U+1F50 */ {0x03c5, 0x0313}, /* U+1F80 */ {0x1f00, 0x03b9},
+	/* U+1F81 */ {0x1f01, 0x03b9}, /* U+1F82 */ {0x1f02, 0x03b9},
+	/* U+1F83 */ {0x1f03, 0x03b9}, /* U+1F84 */ {0x1f04, 0x03b9},
+	/* U+1F85 */ {0x1f05, 0x03b9}, /* U+1F86 */ {0x1f06, 0x03b9},
+	/* U+1F87 */ {0x1f07, 0x03b9}, /* U+1F88 */ {0x1f00, 0x03b9},
+	/* U+1F89 */ {0x1f01, 0x03b9}, /* U+1F8A */ {0x1f02, 0x03b9},
+	/* U+1F8B */ {0x1f03, 0x03b9}, /* U+1F8C */ {0x1f04, 0x03b9},
+	/* U+1F8D */ {0x1f05, 0x03b9}, /* U+1F8E */ {0x1f06, 0x03b9},
+	/* U+1F8F */ {0x1f07, 0x03b9}, /* U+1F90 */ {0x1f20, 0x03b9},
+	/* U+1F91 */ {0x1f21, 0x03b9}, /* U+1F92 */ {0x1f22, 0x03b9},
+	/* U+1F93 */ {0x1f23, 0x03b9}, /* U+1F94 */ {0x1f24, 0x03b9},
+	/* U+1F95 */ {0x1f25, 0x03b9}, /* U+1F96 */ {0x1f26, 0x03b9},
+	/* U+1F97 */ {0x1f27, 0x03b9}, /* U+1F98 */ {0x1f20, 0x03b9},
+	/* U+1F99 */ {0x1f21, 0x03b9}, /* U+1F9A */ {0x1f22, 0x03b9},
+	/* U+1F9B */ {0x1f23, 0x03b9}, /* U+1F9C */ {0x1f24, 0x03b9},
+	/* U+1F9D */ {0x1f25, 0x03b9}, /* U+1F9E */ {0x1f26, 0x03b9},
+	/* U+1F9F */ {0x1f27, 0x03b9}, /* U+1FA0 */ {0x1f60, 0x03b9},
+	/* U+1FA1 */ {0x1f61, 0x03b9}, /* U+1FA2 */ {0x1f62, 0x03b9},
+	/* U+1FA3 */ {0x1f63, 0x03b9}, /* U+1FA4 */ {0x1f64, 0x03b9},
+	/* U+1FA5 */ {0x1f65, 0x03b9}, /* U+1FA6 */ {0x1f66, 0x03b9},
+	/* U+1FA7 */ {0x1f67, 0x03b9}, /* U+1FA8 */ {0x1f60, 0x03b9},
+	/* U+1FA9 */ {0x1f61, 0x03b9}, /* U+1FAA */ {0x1f62, 0x03b9},
+	/* U+1FAB */ {0x1f63, 0x03b9}, /* U+1FAC */ {0x1f64, 0x03b9},
+	/* U+1FAD */ {0x1f65, 0x03b9}, /* U+1FAE */ {0x1f66, 0x03b9},
+	/* U+1FAF */ {0x1f67, 0x03b9}, /* U+1FB2 */ {0x1f70, 0x03b9},
+	/* U+1FB3 */ {0x03b1, 0x03b9}, /* U+1FB4 */ {0x03ac, 0x03b9},
+	/* U+1FB6 */ {0x03b1, 0x0342}, /* U+1FBC */ {0x03b1, 0x03b9},
+	/* U+1FC2 */ {0x1f74, 0x03b9}, /* U+1FC3 */ {0x03b7, 0x03b9},
+	/* U+1FC4 */ {0x03ae, 0x03b9}, /* U+1FC6 */ {0x03b7, 0x0342},
+	/* U+1FCC */ {0x03b7, 0x03b9}, /* U+1FD6 */ {0x03b9, 0x0342},
+	/* U+1FE4 */ {0x03c1, 0x0313}, /* U+1FE6 */ {0x03c5, 0x0342},
+	/* U+1FF2 */ {0x1f7c, 0x03b9}, /* U+1FF3 */ {0x03c9, 0x03b9},
+	/* U+1FF4 */ {0x03ce, 0x03b9}, /* U+1FF6 */ {0x03c9, 0x0342},
+	/* U+1FFC */ {0x03c9, 0x03b9}, /* U+FB00 */ {0x0066, 0x0066},
+	/* U+FB01 */ {0x0066, 0x0069}, /* U+FB02 */ {0x0066, 0x006c},
+	/* U+FB05 */ {0x0073, 0x0074}, /* U+FB06 */ {0x0073, 0x0074},
+	/* U+FB13 */ {0x0574, 0x0576}, /* U+FB14 */ {0x0574, 0x0565},
+	/* U+FB15 */ {0x0574, 0x056b}, /* U+FB16 */ {0x057e, 0x0576},
+	/* U+FB17 */ {0x0574, 0x056d},
+};
+
+__uint16_t xfs_case_fold_triple_table[16][3] = {
+	/* U+0390 */ {0x03b9, 0x0308, 0x0301},
+	/* U+03B0 */ {0x03c5, 0x0308, 0x0301},
+	/* U+1F52 */ {0x03c5, 0x0313, 0x0300},
+	/* U+1F54 */ {0x03c5, 0x0313, 0x0301},
+	/* U+1F56 */ {0x03c5, 0x0313, 0x0342},
+	/* U+1FB7 */ {0x03b1, 0x0342, 0x03b9},
+	/* U+1FC7 */ {0x03b7, 0x0342, 0x03b9},
+	/* U+1FD2 */ {0x03b9, 0x0308, 0x0300},
+	/* U+1FD3 */ {0x03b9, 0x0308, 0x0301},
+	/* U+1FD7 */ {0x03b9, 0x0308, 0x0342},
+	/* U+1FE2 */ {0x03c5, 0x0308, 0x0300},
+	/* U+1FE3 */ {0x03c5, 0x0308, 0x0301},
+	/* U+1FE7 */ {0x03c5, 0x0308, 0x0342},
+	/* U+1FF7 */ {0x03c9, 0x0342, 0x03b9},
+	/* U+FB03 */ {0x0066, 0x0066, 0x0069},
+	/* U+FB04 */ {0x0066, 0x0066, 0x006c},
+};
+
+static __uint16_t xfs_case_fold_turkic_adjust[2][2] = {
+	{0x0049, 0x0131}, {0x0130, 0x0069},
+};
+
+#define NUM_CFT		3
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+int
+libxfs_create_casefoldtable(
+	xfs_mount_t		*mp,
+	int			isturkic)
+{
+	int			i;
+	xfs_dcft_t 		*table;
+	int			table_size;
+	__be16			*cfc;
+	xfs_trans_t		*tp;
+	xfs_inode_t		*cftip;
+	struct cred		creds;
+	struct fsxattr		fsxattrs;
+	xfs_dfiloff_t		bno;
+	int			committed;
+	xfs_bmbt_irec_t		*ep;
+	int			error;
+	xfs_fsblock_t		first;
+	xfs_bmap_free_t		flist;
+	xfs_bmbt_irec_t		map[XFS_BMAP_MAX_NMAP];
+	xfs_extlen_t		nblocks;
+	int			nmap;
+	char			*p;
+	xfs_buf_t		*bp;
+
+	if (!xfs_sb_version_hasunicode(&mp->m_sb))
+		return 0;
+
+	/*
+	 * setup on-disk table in a memory buffer
+	 */
+	table_size = sizeof(xfs_dcft_t) + sizeof(__be32) * (NUM_CFT - 1) +
+			sizeof(xfs_case_fold_table) +
+			sizeof(xfs_case_fold_double_table) +
+			sizeof(xfs_case_fold_triple_table);
+	nblocks = XFS_B_TO_FSB(mp, table_size);
+	table = calloc(1, XFS_FSB_TO_B(mp, nblocks));
+	table->cft_magic = cpu_to_be32(XFS_CFT_MAGIC);
+	platform_uuid_copy(&table->cft_uuid, &mp->m_sb.sb_uuid);
+	table->cft_num_tables = cpu_to_be32(NUM_CFT);
+	table->cft_table_offset[0] = cpu_to_be32(sizeof(xfs_dcft_t) +
+					sizeof(__be32) * (NUM_CFT - 1));
+	table->cft_table_offset[1] = cpu_to_be32(sizeof(xfs_dcft_t) +
+					sizeof(__be32) * (NUM_CFT - 1) +
+					sizeof(xfs_case_fold_table));
+	table->cft_table_offset[2] = cpu_to_be32(sizeof(xfs_dcft_t) +
+					sizeof(__be32) * (NUM_CFT - 1) +
+					sizeof(xfs_case_fold_table) +
+					sizeof(xfs_case_fold_double_table));
+	/* if user wants turkic case folding, adjust table first */
+	if (isturkic) {
+		table->cft_flags |= cpu_to_be32(XFS_CFT_FLAG_TURKIC);
+		for (i = 0; i < ARRAY_SIZE(xfs_case_fold_turkic_adjust); i++) {
+			__uint16_t tmp = xfs_case_fold_table[
+					xfs_case_fold_turkic_adjust[i][0] >> 8];
+			xfs_case_fold_table[tmp +
+				(xfs_case_fold_turkic_adjust[i][0] & 0xff)] =
+					xfs_case_fold_turkic_adjust[i][1];
+		}
+	}
+	cfc = XFS_DCFT_PTR(table, 0);
+	for (i = 0; i < ARRAY_SIZE(xfs_case_fold_table); i++)
+		*cfc++ = cpu_to_be16(xfs_case_fold_table[i]);
+	ASSERT(cfc == XFS_DCFT_PTR(table, 1));
+	for (i = 0; i < ARRAY_SIZE(xfs_case_fold_double_table); i++) {
+		*cfc++ = cpu_to_be16(xfs_case_fold_double_table[i][0]);
+		*cfc++ = cpu_to_be16(xfs_case_fold_double_table[i][1]);
+	}
+	ASSERT(cfc == XFS_DCFT_PTR(table, 2));
+	for (i = 0; i < ARRAY_SIZE(xfs_case_fold_triple_table); i++) {
+		*cfc++ = cpu_to_be16(xfs_case_fold_triple_table[i][0]);
+		*cfc++ = cpu_to_be16(xfs_case_fold_triple_table[i][1]);
+		*cfc++ = cpu_to_be16(xfs_case_fold_triple_table[i][2]);
+	}
+
+	/*
+	 * allocate the inode
+	 */
+	tp = libxfs_trans_alloc(mp, 0);
+	error =  libxfs_trans_reserve(tp, XFS_CREATE_LOG_RES(mp), 0, 0, 0, 0);
+	if (error) {
+		fprintf(stderr, _("%s: cannot reserve space: %s\n"),
+			progname, strerror(error));
+		exit(1);
+	}
+	bzero(&creds, sizeof(creds));
+	bzero(&fsxattrs, sizeof(fsxattrs));
+	error = libxfs_inode_alloc(&tp, NULL, S_IFREG, 1, 0,
+					&creds, &fsxattrs, &cftip);
+	if (error)
+		goto err_out;
+	mp->m_sb.sb_cftino = cftip->i_ino;
+	cftip->i_d.di_size = table_size;
+	libxfs_trans_log_inode(tp, cftip, XFS_ILOG_CORE);
+	libxfs_mod_sb(tp, XFS_SB_CFTINO);
+	libxfs_trans_ihold(tp, cftip);
+	libxfs_trans_commit(tp, 0, NULL);
+
+	/*
+	 * write case table to inode
+	 */
+	tp = libxfs_trans_alloc(mp, 0);
+	error = libxfs_trans_reserve(tp,
+			nblocks + (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1),
+			0, 0, 0, 0);
+	if (error) {
+		fprintf(stderr, _("%s: cannot reserve space: %s\n"),
+			progname, strerror(error));
+		exit(1);
+	}
+	libxfs_trans_ijoin(tp, cftip, 0);
+	bno = 0;
+	p = (char *)table;
+	XFS_BMAP_INIT(&flist, &first);
+	while (bno < nblocks) {
+		nmap = XFS_BMAP_MAX_NMAP;
+		error = libxfs_bmapi(tp, cftip, bno,
+				(xfs_extlen_t)(nblocks - bno),
+				XFS_BMAPI_WRITE, &first, nblocks,
+				map, &nmap, &flist);
+		if (error)
+			goto err_out;
+		for (i = 0, ep = map; i < nmap; i++, ep++) {
+			bp = libxfs_getbuf(mp->m_dev,
+					XFS_FSB_TO_DADDR(mp, ep->br_startblock),
+					XFS_FSB_TO_BB(mp, ep->br_blockcount));
+			memcpy(XFS_BUF_PTR(bp), p, XFS_BUF_SIZE(bp));
+			libxfs_writebuf(bp, 0);
+			bno += ep->br_blockcount;
+			p += XFS_BUF_SIZE(bp);
+		}
+	}
+	error = libxfs_bmap_finish(&tp, &flist, first, &committed);
+	if (error)
+		goto err_out;
+	libxfs_trans_commit(tp, 0, NULL);
+	free(table);
+	return 0;
+
+err_out:
+	libxfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
+	free(table);
+	return error;
+}
Index: ci/xfsprogs/libxfs/xfs_mount.c
===================================================================
--- ci.orig/xfsprogs/libxfs/xfs_mount.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/libxfs/xfs_mount.c	2008-01-18 15:00:08.836596146 +1100
@@ -140,6 +140,8 @@
     { offsetof(xfs_sb_t, sb_logsectsize),0 },
     { 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 }
 };
 
Index: ci/xfsprogs/mkfs/proto.c
===================================================================
--- ci.orig/xfsprogs/mkfs/proto.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/mkfs/proto.c	2008-01-18 15:00:08.912586396 +1100
@@ -18,6 +18,7 @@
 
 #include <xfs/libxfs.h>
 #include <sys/stat.h>
+#include <casefoldtable.h>
 #include "xfs_mkfs.h"
 
 /*
@@ -32,6 +33,7 @@
 	xfs_fsblock_t *first, int dolocal, int logit, char *buf, int len);
 static char *newregfile(char **pp, int *len);
 static void rtinit(xfs_mount_t *mp);
+static void cftinit(xfs_mount_t *mp);
 static long filesize(int fd);
 
 /*
@@ -570,11 +572,13 @@
 		libxfs_trans_ihold(tp, ip);
 		libxfs_trans_commit(tp, 0, NULL);
 		/*
-		 * RT initialization.  Do this here to ensure that
-		 * the RT inodes get placed after the root inode.
+		 * RT & CFT initialization.  Do this here to ensure that
+		 * the RT & CFT inodes get placed after the root inode.
 		 */
-		if (isroot)
+		if (isroot) {
 			rtinit(mp);
+			cftinit(mp);
+		}
 		tp = NULL;
 		for (;;) {
 			name = getstr(pp);
@@ -762,6 +766,20 @@
 	}
 }
 
+/*
+ * Allocate unicode case folding table
+ */
+
+static void
+cftinit(
+	xfs_mount_t		*mp)
+{
+	int	error = libxfs_create_casefoldtable(mp,
+				mp->m_flags & LIBXFS_MOUNT_FLAG_TURKIC_CASE);
+	if (error)
+		fail(_("Creating the case folding table failed"), error);
+}
+
 static long
 filesize(
 	int		fd)
Index: ci/xfsprogs/mkfs/xfs_mkfs.c
===================================================================
--- ci.orig/xfsprogs/mkfs/xfs_mkfs.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/mkfs/xfs_mkfs.c	2008-01-18 15:00:08.916585883 +1100
@@ -128,6 +128,8 @@
 	"size",
 #define	N_VERSION	2
 	"version",
+#define N_UTF8		3
+	"utf8",
 	NULL,
 };
 
@@ -635,7 +637,6 @@
 	char			*dfile;
 	int			dirblocklog;
 	int			dirblocksize;
-	int			dirversion;
 	char			*dsize;
 	int			dsu;
 	int			dsw;
@@ -683,6 +684,8 @@
 	xfs_alloc_rec_t		*nrec;
 	int			nsflag;
 	int			nvflag;
+	int			nci;
+	int			nutf8;
 	int			Nflag;
 	char			*p;
 	char			*protofile;
@@ -707,12 +710,20 @@
 	int 			xlv_dsunit;
 	int			xlv_dswidth;
 	int			lazy_sb_counters;
+	char			*locale;
+	int			isturkiclocale;
+
 
 	progname = basename(argv[0]);
-	setlocale(LC_ALL, "");
+	locale = setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 
+	isturkiclocale = strncasecmp(locale, "az_", 3) == 0 ||
+			strncasecmp(locale, "aze_", 4) == 0 ||
+			strncasecmp(locale, "tr_", 3) == 0 ||
+			strncasecmp(locale, "tur_", 4) == 0;
+
 	attrversion = 2;
 	blflag = bsflag = slflag = ssflag = lslflag = lssflag = 0;
 	blocklog = blocksize = 0;
@@ -724,8 +735,8 @@
 	loginternal = 1;
 	logversion = 2;
 	logagno = logblocks = rtblocks = rtextblocks = 0;
-	Nflag = nlflag = nsflag = nvflag = 0;
-	dirblocklog = dirblocksize = dirversion = 0;
+	Nflag = nlflag = nsflag = nvflag = nci = nutf8 = 0;
+	dirblocklog = dirblocksize = 0;
 	qflag = 0;
 	imaxpct = inodelog = inopblock = isize = 0;
 	iaflag = XFS_IFLAG_ALIGN;
@@ -1240,11 +1251,27 @@
 						reqval('n', nopts, N_VERSION);
 					if (nvflag)
 						respec('n', nopts, N_VERSION);
-					dirversion = atoi(value);
-					if (dirversion < 1 || dirversion > 2)
-						illegal(value, "n version");
+					if (!strcmp(value, "ci")) {
+						nci = 1; /* old-style CI mode */
+					} else {
+						if (atoi(value) != XFS_DFL_DIR_VERSION)
+							illegal(value,
+								"n version");
+					}
 					nvflag = 1;
 					break;
+				case N_UTF8:
+					if (value) {
+						if (!strcmp(value, "turkic"))
+							nutf8 = 2;
+						else
+						if (!strcmp(value, "default"))
+							nutf8 = 1;
+						else
+							illegal(value, "n utf8");
+					} else
+						nutf8 = isturkiclocale ? 2 : 1;
+					break;
 				default:
 					unknown('n', value);
 				}
@@ -1416,33 +1443,24 @@
 		logversion = 2;
 	}
 
-	if (!nvflag)
-		dirversion = (nsflag || nlflag) ? 2 : XFS_DFL_DIR_VERSION;
-	switch (dirversion) {
-	case 1:
-		if ((nsflag || nlflag) && dirblocklog != blocklog) {
+	if (nsflag || nlflag) {
+		if (dirblocksize < blocksize ||
+		    dirblocksize > XFS_MAX_BLOCKSIZE) {
 			fprintf(stderr, _("illegal directory block size %d\n"),
 				dirblocksize);
 			usage();
 		}
-		break;
-	case 2:
-		if (nsflag || nlflag) {
-			if (dirblocksize < blocksize ||
-			    dirblocksize > XFS_MAX_BLOCKSIZE) {
-				fprintf(stderr,
-					_("illegal directory block size %d\n"),
-					dirblocksize);
-				usage();
-			}
-		} else {
-			if (blocksize < (1 << XFS_MIN_REC_DIRSIZE))
-				dirblocklog = XFS_MIN_REC_DIRSIZE;
-			else
-				dirblocklog = blocklog;
-			dirblocksize = 1 << dirblocklog;
-		}
-		break;
+	} else {
+		if (blocksize < (1 << XFS_MIN_REC_DIRSIZE))
+			dirblocklog = XFS_MIN_REC_DIRSIZE;
+		else
+			dirblocklog = blocklog;
+		dirblocksize = 1 << dirblocklog;
+	}
+	if (nci && nutf8) {
+		fprintf(stderr,
+	_("both -n version=ci and utf8= specified, use one or the other\n"));
+		usage();
 	}
 
 	if (daflag && dasize) {
@@ -1717,7 +1735,7 @@
 			sectorsize, xi.rtbsize);
 	}
 
-	max_tr_res = max_trans_res(dirversion,
+	max_tr_res = max_trans_res(XFS_DFL_DIR_VERSION,
 				   sectorlog, blocklog, inodelog, dirblocklog);
 	ASSERT(max_tr_res);
 	min_logblocks = max_tr_res * XFS_MIN_LOG_FACTOR;
@@ -2022,7 +2040,7 @@
 		   "         =%-22s sectsz=%-5u attr=%u\n"
 		   "data     =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
 		   "         =%-22s sunit=%-6u swidth=%u blks\n"
-		   "naming   =version %-14u bsize=%-6u\n"
+		   "naming   =version %-14s bsize=%-6u utf8=%s\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"),
@@ -2031,7 +2049,8 @@
 			"", blocksize, (long long)dblocks,
 			       calc_default_imaxpct(blocklog, dblocks),
 			"", dsunit, dswidth,
-			dirversion, dirversion == 1 ? blocksize : dirblocksize,
+			nci ? "ci" : "2" /*dirversion*/, dirblocksize,
+			nutf8 == 0 ? "none" : nutf8 == 2 ? "turkic" : "default",
 			logfile, 1 << blocklog, (long long)logblocks,
 			logversion, "", lsectorsize, lsunit, lazy_sb_counters,
 			rtfile, rtextblocks << blocklog,
@@ -2076,8 +2095,7 @@
 	sbp->sb_qflags = 0;
 	sbp->sb_unit = dsunit;
 	sbp->sb_width = dswidth;
-	if (dirversion == 2)
-		sbp->sb_dirblklog = dirblocklog - blocklog;
+	sbp->sb_dirblklog = dirblocklog - blocklog;
 	if (logversion == 2) {	/* This is stored in bytes */
 		lsunit = (lsunit == 0) ? 1 : XFS_FSB_TO_B(mp, lsunit);
 		sbp->sb_logsunit = lsunit;
@@ -2095,12 +2113,13 @@
 		sbp->sb_logsectlog = 0;
 		sbp->sb_logsectsize = 0;
 	}
-	sbp->sb_features2 = XFS_SB_VERSION2_MKFS(lazy_sb_counters, attrversion == 2, 0);
+	sbp->sb_features2 = XFS_SB_VERSION2_MKFS(lazy_sb_counters,
+				attrversion == 2, 0, nutf8 != 0);
 	sbp->sb_versionnum = XFS_SB_VERSION_MKFS(
-			iaflag, dsunit != 0,
-			dirversion == 2, logversion == 2, attrversion == 1,
+			iaflag, dsunit != 0, logversion == 2, attrversion == 1,
 			(sectorsize != BBSIZE || lsectorsize != BBSIZE),
-			sbp->sb_features2 != 0);
+			nci != 0, sbp->sb_features2 != 0);
+	sbp->sb_cftino = 0;
 
 	if (force_overwrite)
 		zero_old_xfs_structures(&xi, sbp);
@@ -2162,6 +2181,8 @@
 			progname);
 		exit(1);
 	}
+	if (nutf8 == 2)
+		mp->m_flags |= LIBXFS_MOUNT_FLAG_TURKIC_CASE;
 
 	for (agno = 0; agno < agcount; agno++) {
 		/*
@@ -2574,7 +2595,7 @@
 			    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=n]\n\
+/* naming */		[-n log=n|size=num,version=n,utf8=none|default|turkic]\n\
 /* prototype file */	[-p fname]\n\
 /* quiet */		[-q]\n\
 /* realtime subvol */	[-r extsize=num,size=num,rtdev=xxx]\n\
Index: ci/xfsprogs/mkfs/xfs_mkfs.h
===================================================================
--- ci.orig/xfsprogs/mkfs/xfs_mkfs.h	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/mkfs/xfs_mkfs.h	2008-01-18 15:00:08.924584857 +1100
@@ -20,25 +20,27 @@
 
 #define XFS_DFL_SB_VERSION_BITS \
                 (XFS_SB_VERSION_NLINKBIT | \
-                 XFS_SB_VERSION_EXTFLGBIT)
+                 XFS_SB_VERSION_EXTFLGBIT | \
+                 XFS_SB_VERSION_DIRV2BIT)
 
-#define XFS_SB_VERSION_MKFS(ia,dia,dir2,log2,attr1,sflag,more) (\
-	((ia)||(dia)||(dir2)||(log2)||(attr1)||(sflag)||(more)) ? \
+#define XFS_SB_VERSION_MKFS(ia,dia,log2,attr1,sflag,ci,more) (\
+	((ia)||(dia)||(log2)||(attr1)||(sflag)||(more)) ? \
 	( XFS_SB_VERSION_4 |						\
 		((ia) ? XFS_SB_VERSION_ALIGNBIT : 0) |			\
 		((dia) ? XFS_SB_VERSION_DALIGNBIT : 0) |		\
-		((dir2) ? XFS_SB_VERSION_DIRV2BIT : 0) |		\
 		((log2) ? XFS_SB_VERSION_LOGV2BIT : 0) |		\
 		((attr1) ? XFS_SB_VERSION_ATTRBIT : 0) |		\
 		((sflag) ? XFS_SB_VERSION_SECTORBIT : 0) |		\
+		((ci) ? XFS_SB_VERSION_OLDCIBIT : 0) |			\
 		((more) ? XFS_SB_VERSION_MOREBITSBIT : 0) |		\
 	        XFS_DFL_SB_VERSION_BITS |                               \
 	0 ) : XFS_SB_VERSION_1 )
 
-#define XFS_SB_VERSION2_MKFS(lazycount, attr2, parent) (\
+#define XFS_SB_VERSION2_MKFS(lazycount, attr2, parent, unicode) (\
 	((lazycount) ? XFS_SB_VERSION2_LAZYSBCOUNTBIT : 0) |		\
 	((attr2) ? XFS_SB_VERSION2_ATTR2BIT : 0) |			\
 	((parent) ? XFS_SB_VERSION2_PARENTBIT : 0) |			\
+	((unicode) ? XFS_SB_VERSION2_UNICODEBIT : 0) |			\
 	0 )
 
 #define	XFS_DFL_BLOCKSIZE_LOG	12		/* 4096 byte blocks */
@@ -65,6 +67,7 @@
 
 #define XFS_MAX_AGNUMBER	((xfs_agnumber_t)(NULLAGNUMBER - 1))
 
+#define LIBXFS_MOUNT_FLAG_TURKIC_CASE	0x1000 /* use turkic casefold table */
 
 /* xfs_mkfs.c */
 extern void usage (void);
Index: ci/xfsprogs/repair/agheader.c
===================================================================
--- ci.orig/xfsprogs/repair/agheader.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/repair/agheader.c	2008-01-18 15:00:08.984577159 +1100
@@ -245,10 +245,14 @@
 		 * work against older filesystems when the superblock
 		 * gets rev'ed again with new fields appended.
 		 */
-		if (XFS_SB_VERSION_HASMOREBITS(sb))
-			size = (__psint_t)&sb->sb_features2
-				+ sizeof(sb->sb_features2) - (__psint_t)sb;
-		else if (XFS_SB_VERSION_HASLOGV2(sb))
+		if (XFS_SB_VERSION_HASMOREBITS(sb)) {
+			if (xfs_sb_version_hasunicode(sb))
+				size = (__psint_t)&sb->sb_cftino
+					+ sizeof(sb->sb_cftino) - (__psint_t)sb;
+			else
+				size = (__psint_t)&sb->sb_features2
+					+ sizeof(sb->sb_features2) - (__psint_t)sb;
+		} else if (XFS_SB_VERSION_HASLOGV2(sb))
 			size = (__psint_t)&sb->sb_logsunit
 				+ sizeof(sb->sb_logsunit) - (__psint_t)sb;
 		else if (XFS_SB_VERSION_HASSECTOR(sb))
Index: ci/xfsprogs/repair/dir2.c
===================================================================
--- ci.orig/xfsprogs/repair/dir2.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/repair/dir2.c	2008-01-18 15:00:09.004574594 +1100
@@ -932,6 +932,9 @@
 		} else if (lino == mp->m_sb.sb_gquotino)  {
 			junkit = 1;
 			junkreason = _("group quota");
+		} else if (lino == mp->m_sb.sb_cftino)  {
+			junkit = 1;
+			junkreason = _("casefold table");
 		} else if ((irec_p = find_inode_rec(XFS_INO_TO_AGNO(mp, lino),
 					XFS_INO_TO_AGINO(mp, lino))) != NULL) {
 			/*
Index: ci/xfsprogs/repair/incore.h
===================================================================
--- ci.orig/xfsprogs/repair/incore.h	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/repair/incore.h	2008-01-18 15:00:09.012573567 +1100
@@ -307,6 +307,7 @@
 #define XR_INO_SOCK	9		/* socket */
 #define XR_INO_FIFO	10		/* fifo */
 #define XR_INO_MOUNTPOINT 11		/* mountpoint */
+#define XR_INO_CFT	12		/* casefold table */
 
 /* inode allocation tree */
 
Index: ci/xfsprogs/repair/phase6.c
===================================================================
--- ci.orig/xfsprogs/repair/phase6.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/repair/phase6.c	2008-01-18 15:00:09.016573054 +1100
@@ -17,6 +17,7 @@
  */
 
 #include <libxfs.h>
+#include <casefoldtable.h>
 #include "avl.h"
 #include "globals.h"
 #include "agheader.h"
@@ -94,6 +95,7 @@
 static int
 dir_hash_add(
 	dir_hash_tab_t		*hashtab,
+	xfs_inode_t		*ip,
 	__uint32_t		addr,
 	xfs_ino_t		inum,
 	int			namelen,
@@ -113,7 +115,7 @@
 	dup = 0;
 
 	if (!junk) {
-		hash = libxfs_da_hashname(name, namelen);
+		hash = xfs_dir_hashname(ip, name, namelen);
 		byhash = DIR_HASH_FUNC(hashtab, hash);
 
 		/*
@@ -797,6 +799,18 @@
 }
 
 /*
+ * Makes new case fold table. Default it to a normal table and do checks
+ * during the hashing for possible turkic case, and adjust then if required.
+ */
+void
+mk_cftino(xfs_mount_t *mp)
+{
+	int	error = libxfs_create_casefoldtable(mp, 0);
+	if (error)
+		do_error(_("Creating the casefold table failed"), error);
+}
+
+/*
  * orphanage name == lost+found
  */
 xfs_ino_t
@@ -1092,7 +1106,6 @@
  */
 static xfs_dfsbno_t
 map_first_dblock_fsbno(xfs_mount_t	*mp,
-			xfs_ino_t	ino,
 			xfs_inode_t	*ip,
 			xfs_dablk_t	*bno)
 {
@@ -1127,11 +1140,11 @@
 		if (!no_modify)
 			do_error(
 _("can't map block %d in %s inode %llu, xfs_bmapi returns %d, nmap = %d\n"),
-				da_bno, ftype, ino, error, nmap);
+				da_bno, ftype, ip->i_ino, error, nmap);
 		else  {
 			do_warn(
 _("can't map block %d in %s inode %llu, xfs_bmapi returns %d, nmap = %d\n"),
-				da_bno, ftype, ino, error, nmap);
+				da_bno, ftype, ip->i_ino, error, nmap);
 			return(NULLDFSBNO);
 		}
 	}
@@ -1139,10 +1152,10 @@
 	if ((fsbno = map.br_startblock) == HOLESTARTBLOCK)  {
 		if (!no_modify)
 			do_error(_("block %d in %s ino %llu doesn't exist\n"),
-				da_bno, ftype, ino);
+				da_bno, ftype, ip->i_ino);
 		else  {
 			do_warn(_("block %d in %s ino %llu doesn't exist\n"),
-				da_bno, ftype, ino);
+				da_bno, ftype, ip->i_ino);
 			return(NULLDFSBNO);
 		}
 	}
@@ -1167,7 +1180,7 @@
 		if (!bp) {
 			do_warn(
 	_("can't read block %u (fsbno %llu) for directory inode %llu\n"),
-					da_bno, fsbno, ino);
+					da_bno, fsbno, ip->i_ino);
 			return(NULLDFSBNO);
 		}
 
@@ -1177,7 +1190,7 @@
 			libxfs_putbuf(bp);
 			do_warn(
 _("bad dir/attr magic number in inode %llu, file bno = %u, fsbno = %llu\n"),
-				ino, da_bno, fsbno);
+				ip->i_ino, da_bno, fsbno);
 			return(NULLDFSBNO);
 		}
 
@@ -1197,11 +1210,11 @@
 			if (!no_modify)
 				do_error(
 _("can't map block %d in %s ino %llu, xfs_bmapi returns %d, nmap = %d\n"),
-					da_bno, ftype, ino, error, nmap);
+					da_bno, ftype, ip->i_ino, error, nmap);
 			else  {
 				do_warn(
 _("can't map block %d in %s ino %llu, xfs_bmapi returns %d, nmap = %d\n"),
-					da_bno, ftype, ino, error, nmap);
+					da_bno, ftype, ip->i_ino, error, nmap);
 				return(NULLDFSBNO);
 			}
 		}
@@ -1209,11 +1222,11 @@
 			if (!no_modify)
 				do_error(
 				_("block %d in %s inode %llu doesn't exist\n"),
-					da_bno, ftype, ino);
+					da_bno, ftype, ip->i_ino);
 			else  {
 				do_warn(
 				_("block %d in %s inode %llu doesn't exist\n"),
-					da_bno, ftype, ino);
+					da_bno, ftype, ip->i_ino);
 				return(NULLDFSBNO);
 			}
 		}
@@ -1236,8 +1249,7 @@
  * this routine can NOT be called if running in no modify mode
  */
 static int
-prune_lf_dir_entry(xfs_mount_t *mp, xfs_ino_t ino, xfs_inode_t *ip,
-			xfs_dahash_t *hashval)
+prune_lf_dir_entry(xfs_mount_t *mp, xfs_inode_t *ip, xfs_dahash_t *hashval)
 {
 	xfs_dfsbno_t		fsbno;
 	int			i;
@@ -1280,7 +1292,7 @@
 	namest = NULL;
 	fblock = NULLFSBLOCK;
 
-	fsbno = map_first_dblock_fsbno(mp, ino, ip, &da_bno);
+	fsbno = map_first_dblock_fsbno(mp, ip, &da_bno);
 
 	/*
 	 * now go foward along the leaves of the btree looking
@@ -1293,7 +1305,7 @@
 		if (!bp)  {
 			do_error(
 	_("can't read directory inode %llu (leaf) block %u (fsbno %llu)\n"),
-				ino, da_bno, fsbno);
+				ip->i_ino, da_bno, fsbno);
 			/* NOTREACHED */
 		}
 
@@ -1335,12 +1347,12 @@
 				if (error || nmap != 1)
 					do_error(
 _("can't map block %d in directory %llu, xfs_bmapi returns %d, nmap = %d\n"),
-						da_bno, ino, error, nmap);
+						da_bno, ip->i_ino, error, nmap);
 				if ((fsbno = map.br_startblock)
 						== HOLESTARTBLOCK)  {
 					do_error(
 				_("%s ino %llu block %d doesn't exist\n"),
-						ftype, ino, da_bno);
+						ftype, ip->i_ino, da_bno);
 				}
 			}
 		}
@@ -1395,7 +1407,7 @@
 	if (error)  {
 		do_error(
 _("couldn't remove bogus entry \"%s\" in\n\tdirectory inode %llu, errno = %d\n"),
-			fname, ino, error);
+			fname, ip->i_ino, error);
 		/* NOTREACHED */
 	}
 
@@ -1432,7 +1444,7 @@
  */
 static void
 lf_block_dir_entry_check(xfs_mount_t		*mp,
-			xfs_ino_t		ino,
+			xfs_inode_t		*ip,
 			xfs_dir_leafblock_t	*leaf,
 			int			*dirty,
 			int			*num_illegal,
@@ -1516,7 +1528,7 @@
 		 * '..' is already accounted for or will be taken care
 		 * of when directory is moved to orphanage.
 		 */
-		if (ino == lino)  {
+		if (ip->i_ino == lino)  {
 			ASSERT(namest->name[0] == '.' && entry->namelen == 1);
 			add_inode_ref(current_irec, current_ino_offset);
 			*need_dot = 0;
@@ -1539,7 +1551,7 @@
 			nbad++;
 			if (entry_junked(_("entry \"%s\" in dir inode %llu "
 					"points to non-existent inode %llu"),
-					fname, ino, lino)) {
+					fname, ip->i_ino, lino)) {
 				namest->name[0] = '/';
 				*dirty = 1;
 			}
@@ -1557,7 +1569,7 @@
 			nbad++;
 			if (entry_junked(_("entry \"%s\" in dir inode %llu "
 					"points to free inode %llu"),
-					fname, ino, lino)) {
+					fname, ip->i_ino, lino)) {
 				namest->name[0] = '/';
 				*dirty = 1;
 			}
@@ -1566,14 +1578,15 @@
 		/*
 		 * check if this inode is lost+found dir in the root
 		 */
-		if (ino == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) {
+		if (ip->i_ino == mp->m_sb.sb_rootino &&
+				strcmp(fname, ORPHANAGE) == 0) {
 			/* root inode, "lost+found", if it's not a directory,
 			 * trash it, otherwise, assign it */
 			if (!inode_isadir(irec, ino_offset)) {
 				nbad++;
 				if (entry_junked(_("%s (ino %llu) in root "
 						"(%llu) is not a directory"),
-						ORPHANAGE, lino, ino)) {
+						ORPHANAGE, lino, ip->i_ino)) {
 					namest->name[0] = '/';
 					*dirty = 1;
 				}
@@ -1589,13 +1602,13 @@
 		/*
 		 * check for duplicate names in directory.
 		 */
-		if (!dir_hash_add(hashtab, (da_bno << mp->m_sb.sb_blocklog) +
-				entry->nameidx, lino, entry->namelen,
-				namest->name)) {
+		if (!dir_hash_add(hashtab, ip, (da_bno <<
+					mp->m_sb.sb_blocklog) + entry->nameidx,
+				lino, entry->namelen, namest->name)) {
 			nbad++;
 			if (entry_junked(_("entry \"%s\" (ino %llu) in dir "
 					"%llu is a duplicate name"),
-					fname, lino, ino)) {
+					fname, lino, ip->i_ino)) {
 				namest->name[0] = '/';
 				*dirty = 1;
 			}
@@ -1626,15 +1639,15 @@
 			junkit = 1;
 			do_warn(
 _("entry \"%s\" in dir %llu points to an already connected dir inode %llu,\n"),
-				fname, ino, lino);
-		} else if (parent == ino)  {
+				fname, ip->i_ino, lino);
+		} else if (parent == ip->i_ino)  {
 			add_inode_reached(irec, ino_offset);
 			add_inode_ref(current_irec, current_ino_offset);
 		} else  {
 			junkit = 1;
 			do_warn(
 _("entry \"%s\" in dir ino %llu not consistent with .. value (%llu) in ino %llu,\n"),
-				fname, ino, parent, lino);
+				fname, ip->i_ino, parent, lino);
 		}
 
 		if (junkit)  {
@@ -1666,7 +1679,6 @@
  */
 static void
 longform_dir_entry_check(xfs_mount_t	*mp,
-			xfs_ino_t	ino,
 			xfs_inode_t	*ip,
 			int		*num_illegal,
 			int		*need_dot,
@@ -1691,10 +1703,11 @@
 	*need_dot = 1;
 	ftype = _("dir");
 
-	fsbno = map_first_dblock_fsbno(mp, ino, ip, &da_bno);
+	fsbno = map_first_dblock_fsbno(mp, ip, &da_bno);
 
 	if (fsbno == NULLDFSBNO && no_modify)  {
-		do_warn(_("cannot map block 0 of directory inode %llu\n"), ino);
+		do_warn(_("cannot map block 0 of directory inode %llu\n"),
+				ip->i_ino);
 		return;
 	}
 
@@ -1708,7 +1721,7 @@
 		if (!bp) {
 			do_error(
 	_("can't read block %u (fsbno %llu) for directory inode %llu\n"),
-					da_bno, fsbno, ino);
+					da_bno, fsbno, ip->i_ino);
 			/* NOTREACHED */
 		}
 
@@ -1721,7 +1734,7 @@
 _("bad magic # (0x%x) for dir ino %llu leaf block (bno %u fsbno %llu)\n"),
 					INT_GET(leaf->hdr.info.magic,
 						ARCH_CONVERT),
-					ino, da_bno, fsbno);
+					ip->i_ino, da_bno, fsbno);
 				/* NOTREACHED */
 			} else  {
 				/*
@@ -1734,7 +1747,7 @@
 		}
 
 		if (!skipit)
-			lf_block_dir_entry_check(mp, ino, leaf, &dirty,
+			lf_block_dir_entry_check(mp, ip, leaf, &dirty,
 					num_illegal, need_dot, irec,
 					ino_offset, hashtab, da_bno);
 
@@ -1757,11 +1770,11 @@
 				if (!no_modify)
 					do_error(
 _("can't map leaf block %d in dir %llu, xfs_bmapi returns %d, nmap = %d\n"),
-						da_bno, ino, error, nmap);
+						da_bno, ip->i_ino, error, nmap);
 				else  {
 					do_warn(
 _("can't map leaf block %d in dir %llu, xfs_bmapi returns %d, nmap = %d\n"),
-						da_bno, ino, error, nmap);
+						da_bno, ip->i_ino, error, nmap);
 					return;
 				}
 			}
@@ -1769,11 +1782,11 @@
 				if (!no_modify)
 					do_error(
 				_("block %d in %s ino %llu doesn't exist\n"),
-						da_bno, ftype, ino);
+						da_bno, ftype, ip->i_ino);
 				else  {
 					do_warn(
 				_("block %d in %s ino %llu doesn't exist\n"),
-						da_bno, ftype, ino);
+						da_bno, ftype, ip->i_ino);
 					return;
 				}
 			}
@@ -1788,10 +1801,9 @@
 
 static void
 longform_dir2_rebuild(
-	xfs_mount_t	*mp,
-	xfs_ino_t	ino,
-	xfs_inode_t	*ip,
-	dir_hash_tab_t	*hashtab)
+	xfs_mount_t		*mp,
+	xfs_inode_t		*ip,
+	dir_hash_tab_t		*hashtab)
 {
 	int			error;
 	int			nres;
@@ -1810,7 +1822,7 @@
 	 * name/inode pairs in the hash table
 	 */
 
-	do_warn(_("rebuilding directory inode %llu\n"), ino);
+	do_warn(_("rebuilding directory inode %llu\n"), ip->i_ino);
 
 	/*
 	 * first attempt to locate the parent inode, if it can't be found,
@@ -1891,7 +1903,7 @@
 				nres))) {
 			do_warn(
 _("name create failed in ino %llu (%d), filesystem may be out of space\n"),
-				ino, error);
+				ip->i_ino, error);
 			libxfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
 						XFS_TRANS_ABORT);
 			break;
@@ -2253,9 +2265,24 @@
 				orphanage_ino = inum;
 		}
 		/*
+		 * check for invalid UTF-8 name if Unicode filesystem
+		 */
+		if (xfs_sb_version_hasunicode(&mp->m_sb) &&
+				xfs_unicode_validate((uchar_t *)dep->name,
+					dep->namelen) != 0) {
+			nbad++;
+			if (entry_junked(_("entry \"%s\" (ino %llu) in dir "
+					"%llu is not a valid UTF-8 name"),
+					fname, inum, ip->i_ino)) {
+				dep->name[0] = '/';
+				libxfs_dir2_data_log_entry(tp, bp, dep);
+			}
+			continue;
+		}
+		/*
 		 * check for duplicate names in directory.
 		 */
-		if (!dir_hash_add(hashtab, addr, inum, dep->namelen,
+		if (!dir_hash_add(hashtab, ip, addr, inum, dep->namelen,
 				dep->name)) {
 			nbad++;
 			if (entry_junked(_("entry \"%s\" (ino %llu) in dir "
@@ -2565,7 +2592,6 @@
  */
 static void
 longform_dir2_entry_check(xfs_mount_t	*mp,
-			xfs_ino_t	ino,
 			xfs_inode_t	*ip,
 			int		*num_illegal,
 			int		*need_dot,
@@ -2629,7 +2655,7 @@
 				XFS_DATA_FORK)) {
 			do_warn(_(
 			"can't read data block %u for directory inode %llu\n"),
-				da_bno, ino);
+				da_bno, ip->i_ino);
 			*num_illegal += 1;
 			continue;	/* try and read all "data" blocks */
 		}
@@ -2637,7 +2663,7 @@
 				irec, ino_offset, &bplist[db], hashtab,
 				&freetab, da_bno, isblock);
 	}
-	fixit = (*num_illegal != 0) || dir2_is_badino(ino);
+	fixit = (*num_illegal != 0) || dir2_is_badino(ip->i_ino);
 
 	/* check btree and freespace */
 	if (isblock) {
@@ -2659,7 +2685,7 @@
 		for (i = 0; i < freetab->naents; i++)
 			if (bplist[i])
 				libxfs_da_brelse(NULL, bplist[i]);
-		longform_dir2_rebuild(mp, ino, ip, hashtab);
+		longform_dir2_rebuild(mp, ip, hashtab);
 		*num_illegal = 0;
 	} else {
 		for (i = 0; i < freetab->naents; i++)
@@ -2677,7 +2703,6 @@
  */
 static void
 shortform_dir_entry_check(xfs_mount_t	*mp,
-			xfs_ino_t	ino,
 			xfs_inode_t	*ip,
 			int		*ino_dirty,
 			ino_tree_node_t	*current_irec,
@@ -2726,7 +2751,7 @@
 	if (sf == NULL) {
 		junkit = 1;
 		do_warn(_("shortform dir inode %llu has null data entries \n"),
-			ino);
+			ip->i_ino);
 
 		}
 	else {
@@ -2794,7 +2819,7 @@
 		if (irec == NULL) {
 			do_warn(_("entry \"%s\" in shortform dir %llu "
 				"references non-existent ino %llu"),
-				fname, ino, lino);
+				fname, ip->i_ino, lino);
 			goto do_junkit;
 		}
 		ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum;
@@ -2806,19 +2831,22 @@
 		 */
 		if (!is_inode_free(irec, ino_offset))  {
 			do_warn(_("entry \"%s\" in shortform dir inode %llu "
-				"points to free inode %llu"), fname, ino, lino);
+				"points to free inode %llu"),
+				fname, ip->i_ino, lino);
 			goto do_junkit;
 		}
 		/*
 		 * check if this inode is lost+found dir in the root
 		 */
-		if (ino == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) {
+		if (ip->i_ino == mp->m_sb.sb_rootino &&
+				strcmp(fname, ORPHANAGE) == 0) {
 			/*
 			 * if it's not a directory, trash it
 			 */
 			if (!inode_isadir(irec, ino_offset)) {
 				do_warn(_("%s (ino %llu) in root (%llu) is not "
-					"a directory"), ORPHANAGE, lino, ino);
+					"a directory"),
+					ORPHANAGE, lino, ip->i_ino);
 				goto do_junkit;
 			}
 			/*
@@ -2831,11 +2859,11 @@
 		/*
 		 * check for duplicate names in directory.
 		 */
-		if (!dir_hash_add(hashtab,
+		if (!dir_hash_add(hashtab, ip,
 				(xfs_dir2_dataptr_t)(sf_entry - &sf->list[0]),
 				lino, sf_entry->namelen, sf_entry->name)) {
 			do_warn(_("entry \"%s\" (ino %llu) in dir %llu is a "
-				"duplicate name"), fname, lino, ino);
+				"duplicate name"), fname, lino, ip->i_ino);
 			goto do_junkit;
 		}
 		if (!inode_isadir(irec, ino_offset))  {
@@ -2861,8 +2889,8 @@
 				junkit = 1;
 				do_warn(_("entry \"%s\" in dir %llu references "
 					"already connected dir ino %llu,\n"),
-					fname, ino, lino);
-			} else if (parent == ino)  {
+					fname, ip->i_ino, lino);
+			} else if (parent == ip->i_ino)  {
 				add_inode_reached(irec, ino_offset);
 				add_inode_ref(current_irec, current_ino_offset);
 			} else  {
@@ -2870,7 +2898,7 @@
 				do_warn(_("entry \"%s\" in dir %llu not "
 					"consistent with .. value (%llu) in "
 					"dir ino %llu"),
-					fname, ino, parent, lino);
+					fname, ip->i_ino, parent, lino);
 			}
 		}
 		if (junkit)  {
@@ -2960,7 +2988,7 @@
 
 /* ARGSUSED */
 static void
-prune_sf_dir_entry(xfs_mount_t *mp, xfs_ino_t ino, xfs_inode_t *ip)
+prune_sf_dir_entry(xfs_mount_t *mp, xfs_inode_t *ip)
 {
 				/* REFERENCED */
 	xfs_ino_t		lino;
@@ -3058,7 +3086,6 @@
  */
 static void
 shortform_dir2_entry_check(xfs_mount_t	*mp,
-			xfs_ino_t	ino,
 			xfs_inode_t	*ip,
 			int		*ino_dirty,
 			ino_tree_node_t	*current_irec,
@@ -3188,7 +3215,7 @@
 		if (irec == NULL)  {
 			do_warn(_("entry \"%s\" in shortform directory %llu "
 				  "references non-existent inode %llu"),
-				fname, ino, lino);
+				fname, ip->i_ino, lino);
 			goto do_junkit;
 		}
 
@@ -3202,19 +3229,21 @@
 		if (is_inode_free(irec, ino_offset))  {
 			do_warn(_("entry \"%s\" in shortform directory "
 				  "inode %llu points to free inode %llu"),
-				fname, ino, lino);
+				fname, ip->i_ino, lino);
 			goto do_junkit;
 		}
 		/*
 		 * check if this inode is lost+found dir in the root
 		 */
-		if (ino == mp->m_sb.sb_rootino && strcmp(fname, ORPHANAGE) == 0) {
+		if (ip->i_ino == mp->m_sb.sb_rootino &&
+				strcmp(fname, ORPHANAGE) == 0) {
 			/*
 			 * if it's not a directory, trash it
 			 */
 			if (!inode_isadir(irec, ino_offset)) {
 				do_warn(_("%s (ino %llu) in root (%llu) is not "
-					"a directory"), ORPHANAGE, lino, ino);
+					"a directory"),
+					ORPHANAGE, lino, ip->i_ino);
 				goto do_junkit;
 			}
 			/*
@@ -3225,13 +3254,24 @@
 				orphanage_ino = lino;
 		}
 		/*
+		 * check for invalid UTF-8 name if Unicode filesystem
+		 */
+		if (xfs_sb_version_hasunicode(&mp->m_sb) &&
+				xfs_unicode_validate((uchar_t *)sfep->name,
+					sfep->namelen) != 0) {
+			do_warn(_("entry \"%s\" (ino %llu) in dir %llu is "
+				"not a valid UTF-8 name"),
+				fname, lino, ip->i_ino);
+			goto do_junkit;
+		}
+		/*
 		 * check for duplicate names in directory.
 		 */
-		if (!dir_hash_add(hashtab, (xfs_dir2_dataptr_t)
+		if (!dir_hash_add(hashtab, ip, (xfs_dir2_dataptr_t)
 					(sfep - XFS_DIR2_SF_FIRSTENTRY(sfp)),
 				lino, sfep->namelen, sfep->name)) {
 			do_warn(_("entry \"%s\" (ino %llu) in dir %llu is a "
-				"duplicate name"), fname, lino, ino);
+				"duplicate name"), fname, lino, ip->i_ino);
 			goto do_junkit;
 		}
 		if (!inode_isadir(irec, ino_offset))  {
@@ -3252,17 +3292,17 @@
 				junkit = 1;
 				do_warn(_("entry \"%s\" in directory inode %llu"
 					  " references already connected inode "
-					  "%llu,\n"),
-					fname, ino, lino);
-			} else if (parent == ino)  {
+					  "%llu"),
+					fname, ip->i_ino, lino);
+			} else if (parent == ip->i_ino)  {
 				add_inode_reached(irec, ino_offset);
 				add_inode_ref(current_irec, current_ino_offset);
 			} else  {
 				junkit = 1;
 				do_warn(_("entry \"%s\" in directory inode %llu"
 					  " not consistent with .. value (%llu)"
-					  " in inode %llu,\n"),
-					fname, ino, parent, lino);
+					  " in inode %llu"),
+					fname, ip->i_ino, parent, lino);
 			}
 		}
 
@@ -3302,11 +3342,11 @@
 				*ino_dirty = 1;
 
 				if (verbose)
-					do_warn(_("junking entry\n"));
+					do_warn(_(", junking entry\n"));
 				else
 					do_warn("\n");
 			} else  {
-				do_warn(_("would junk entry\n"));
+				do_warn(_(", would junk entry\n"));
 			}
 		} else if (lino > XFS_DIR2_MAX_SHORT_INUM)
 			i8++;
@@ -3330,7 +3370,8 @@
 
 	if (sfp->hdr.i8count != i8) {
 		if (no_modify) {
-			do_warn(_("would fix i8count in inode %llu\n"), ino);
+			do_warn(_("would fix i8count in inode %llu\n"),
+				ip->i_ino);
 		} else {
 			if (i8 == 0) {
 				tmp_sfep = next_sfep;
@@ -3342,7 +3383,7 @@
 			} else
 				sfp->hdr.i8count = i8;
 			*ino_dirty = 1;
-			do_warn(_("fixing i8count in inode %llu\n"), ino);
+			do_warn(_("fixing i8count in inode %llu\n"), ip->i_ino);
 		}
 	}
 
@@ -3418,6 +3459,7 @@
 		add_inode_refchecked(ino, irec, 0);
 		return;
 	}
+	ASSERT(ip->i_ino == ino);
 
 	need_dot = dirty = num_illegal = 0;
 
@@ -3450,15 +3492,13 @@
 			 * we need to create '.' entries here.
 			 */
 			if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
-				longform_dir2_entry_check(mp, ino, ip,
-							&num_illegal, &need_dot,
-							irec, ino_offset,
-							hashtab);
+				longform_dir2_entry_check(mp, ip, &num_illegal,
+						&need_dot, irec, ino_offset,
+						hashtab);
 			else
-				longform_dir_entry_check(mp, ino, ip,
-							&num_illegal, &need_dot,
-							irec, ino_offset,
-							hashtab);
+				longform_dir_entry_check(mp, ip, &num_illegal,
+						&need_dot, irec, ino_offset,
+						hashtab);
 			break;
 
 		case XFS_DINODE_FMT_LOCAL:
@@ -3481,13 +3521,11 @@
 			libxfs_trans_ihold(tp, ip);
 
 			if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
-				shortform_dir2_entry_check(mp, ino, ip, &dirty,
-							irec, ino_offset,
-							hashtab);
+				shortform_dir2_entry_check(mp, ip, &dirty,
+						irec, ino_offset, hashtab);
 			else
-				shortform_dir_entry_check(mp, ino, ip, &dirty,
-							irec, ino_offset,
-							hashtab);
+				shortform_dir_entry_check(mp, ip, &dirty,
+						irec, ino_offset, hashtab);
 
 			ASSERT(dirty == 0 || (dirty && !no_modify));
 			if (dirty)  {
@@ -3567,7 +3605,7 @@
 
 		while (num_illegal > 0 && ip->i_d.di_format !=
 				XFS_DINODE_FMT_LOCAL)  {
-			prune_lf_dir_entry(mp, ino, ip, &hashval);
+			prune_lf_dir_entry(mp, ip, &hashval);
 			num_illegal--;
 		}
 
@@ -3600,7 +3638,7 @@
 			libxfs_trans_ijoin(tp, ip, 0);
 			libxfs_trans_ihold(tp, ip);
 
-			prune_sf_dir_entry(mp, ino, ip);
+			prune_sf_dir_entry(mp, ip);
 
 			libxfs_trans_log_inode(tp, ip,
 					XFS_ILOG_CORE | XFS_ILOG_DDATA);
@@ -3679,7 +3717,7 @@
 
 /*
  * mark realtime bitmap and summary inodes as reached.
- * quota inode will be marked here as well
+ * quota and casefold table inodes will be marked here as well
  */
 void
 mark_standalone_inodes(xfs_mount_t *mp)
@@ -3707,6 +3745,15 @@
 
 	add_inode_reached(irec, offset);
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_cftino),
+				XFS_INO_TO_AGINO(mp, mp->m_sb.sb_cftino));
+		offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_cftino) -
+				irec->ino_startnum;
+		ASSERT(irec != NULL);
+		add_inode_reached(irec, offset);
+	}
+
 	if (fs_quotas)  {
 		if (mp->m_sb.sb_uquotino
 				&& mp->m_sb.sb_uquotino != NULLFSINO)  {
@@ -3882,6 +3929,15 @@
 		}
 	}
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb) && (mp->m_sb.sb_cftino == 0 ||
+			mp->m_sb.sb_cftino == NULLFSINO)) {
+		if (!no_modify) {
+			do_warn(_("reinitializing casefold table inode\n"));
+			mk_cftino(mp);
+		} else
+			do_warn(_("would reinitializing casefold table inode\n"));
+	}
+
 	if (!no_modify)  {
 		do_log(
 _("        - resetting contents of realtime bitmap and summary inodes\n"));
@@ -3896,6 +3952,11 @@
 		}
 	}
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		if (xfs_unicode_read_cft(mp) != 0)
+			do_error(_("cannot read case folding table\n"));
+	}
+
 	mark_standalone_inodes(mp);
 
 	do_log(_("        - traversing filesystem ...\n"));
Index: ci/xfsprogs/db/check.c
===================================================================
--- ci.orig/xfsprogs/db/check.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/db/check.c	2008-01-18 15:00:09.076565357 +1100
@@ -31,6 +31,7 @@
 #include "output.h"
 #include "init.h"
 #include "malloc.h"
+#include "casefoldtable.h"
 
 typedef enum {
 	IS_USER_QUOTA, IS_PROJECT_QUOTA, IS_GROUP_QUOTA,
@@ -39,11 +40,11 @@
 typedef enum {
 	DBM_UNKNOWN,	DBM_AGF,	DBM_AGFL,	DBM_AGI,
 	DBM_ATTR,	DBM_BTBMAPA,	DBM_BTBMAPD,	DBM_BTBNO,
-	DBM_BTCNT,	DBM_BTINO,	DBM_DATA,	DBM_DIR,
-	DBM_FREE1,	DBM_FREE2,	DBM_FREELIST,	DBM_INODE,
-	DBM_LOG,	DBM_MISSING,	DBM_QUOTA,	DBM_RTBITMAP,
-	DBM_RTDATA,	DBM_RTFREE,	DBM_RTSUM,	DBM_SB,
-	DBM_SYMLINK,
+	DBM_BTCNT,	DBM_BTINO,	DBM_CFT,	DBM_DATA,
+	DBM_DIR,	DBM_FREE1,	DBM_FREE2,	DBM_FREELIST,
+	DBM_INODE,	DBM_LOG,	DBM_MISSING,	DBM_QUOTA,
+	DBM_RTBITMAP,	DBM_RTDATA,	DBM_RTFREE,	DBM_RTSUM,
+	DBM_SB,		DBM_SYMLINK,
 	DBM_NDBM
 } dbm_t;
 
@@ -153,6 +154,7 @@
 	"btbno",
 	"btcnt",
 	"btino",
+	"cft",
 	"data",
 	"dir",
 	"free1",
@@ -224,6 +226,7 @@
 static int		blocktrash_f(int argc, char **argv);
 static int		blockuse_f(int argc, char **argv);
 static int		check_blist(xfs_fsblock_t bno);
+static void		check_cft(void);
 static void		check_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno,
 				    xfs_extlen_t len, dbm_t type);
 static int		check_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno,
@@ -249,7 +252,7 @@
 				       xfs_extlen_t len, int typemask);
 static void		checknot_rdbmap(xfs_drfsbno_t bno, xfs_extlen_t len,
 					int typemask);
-static void		dir_hash_add(xfs_dahash_t hash,
+static void		dir_hash_add(const uchar_t *name, int namelen,
 				     xfs_dir2_dataptr_t addr);
 static void		dir_hash_check(inodata_t *id, int v);
 static void		dir_hash_done(void);
@@ -1227,6 +1230,170 @@
 }
 
 static void
+check_cft(void)
+{
+	xfs_agblock_t		agbno;
+	xfs_agino_t		agino;
+	xfs_dinode_t		*dip;
+	xfs_dinode_core_t	tdic;
+	xfs_extnum_t		nextents = 0;
+	xfs_drfsbno_t		totdblocks = 0;
+	xfs_drfsbno_t		totiblocks = 0;
+	blkmap_t		*blkmap;
+	xfs_dcft_t		*cfthdr;
+	int			off;
+	int			i;
+	xfs_dfsbno_t		fsbno;
+	int			ntables;
+	int			lower_off;
+
+	/*
+	 * Without CRCs, cannot verify the actual table, just the header
+	 * consistency.
+	 */
+	cfthdr = NULL;
+	agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_cftino);
+	agbno = XFS_AGINO_TO_AGBNO(mp, agino);
+	off = XFS_AGINO_TO_OFFSET(mp, agino);
+	if (XFS_INO_TO_AGNO(mp, mp->m_sb.sb_cftino) != 0 ||
+			agbno >= mp->m_sb.sb_agblocks ||
+			off >= mp->m_sb.sb_inopblock) {
+		if (!sflag)
+			dbprintf("bad casefold table inode number %lld\n",
+				mp->m_sb.sb_cftino);
+		goto bad_out;
+	}
+	set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, 0, agbno),
+			blkbb, DB_RING_IGN, NULL);
+	off_cur(off << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize);
+	dip = iocur_top->data;
+
+	libxfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, &tdic, 1);
+	memcpy(&dip->di_core, &tdic, sizeof(xfs_dinode_core_t));
+
+	/* do some basic inode checks */
+	if ((dip->di_core.di_mode & S_IFMT) != S_IFREG) {
+		if (!sflag)
+			dbprintf("casefold table inode mode invalid\n");
+		goto bad_out;
+	}
+	if (dip->di_core.di_format != XFS_DINODE_FMT_EXTENTS) {
+		dbprintf("casefold table inode format invalid\n");
+		goto bad_out;
+	}
+	if (dip->di_core.di_size <= sizeof(xfs_dcft_t) + sizeof(__be32) *
+			XFS_CFT_MAX_NUM_TABLES) {
+		if (!sflag)
+			dbprintf("casefold table inode size too small\n");
+		return;
+	}
+	blkmap = blkmap_alloc(dip->di_core.di_nextents);
+
+	process_exinode(find_inode(mp->m_sb.sb_cftino, 1), dip, DBM_CFT,
+			&totdblocks, &totiblocks, &nextents, &blkmap,
+			XFS_DATA_FORK);
+	ASSERT(totiblocks == 0);
+	if (totdblocks != dip->di_core.di_nblocks) {
+		if (!sflag)
+			dbprintf("bad nblocks %lld for casefold table inode "
+				"%lld, counted %lld\n", dip->di_core.di_nblocks,
+				mp->m_sb.sb_cftino, totdblocks);
+		goto bad_out;
+	}
+	if (nextents != dip->di_core.di_nextents) {
+		if (!sflag)
+			dbprintf("bad nextents %d for casefold table inode "
+				"%lld, counted %d\n", dip->di_core.di_nextents,
+				mp->m_sb.sb_cftino, nextents);
+		goto bad_out;
+	}
+
+	cfthdr = xmalloc(sizeof(xfs_dcft_t) + sizeof(__be32) *
+			XFS_CFT_MAX_NUM_TABLES);
+
+	/* make sure we can read the entire table, should not be sparse */
+	for (i = 0; i < totdblocks; i++) {
+		fsbno = blkmap_get(blkmap, i);
+		if (fsbno == NULLFSBLOCK) {
+			if (!sflag)
+				dbprintf("block %lld for casefold table inode "
+					"is missing\n", (xfs_dfiloff_t)i);
+			goto bad_out;
+		}
+		push_cur();
+		set_cur(&typtab[TYP_CFT], XFS_FSB_TO_DADDR(mp, fsbno), blkbb,
+				DB_RING_IGN, NULL);
+		if (iocur_top->data == NULL) {
+			pop_cur();
+			if (!sflag)
+				dbprintf("can't read block %lld for casfold "
+					 "table inode\n", (xfs_dfiloff_t)i);
+			goto bad_out;
+		}
+		if (i == 0)
+			memcpy(cfthdr, iocur_top->data, sizeof(xfs_dcft_t) +
+				sizeof(__be32) * XFS_CFT_MAX_NUM_TABLES);
+		pop_cur();
+	}
+
+	/* verify contents of the header */
+	if (be32_to_cpu(cfthdr->cft_magic) != XFS_CFT_MAGIC) {
+		if (!sflag)
+			dbprintf("bad magic number 0x%x in casefold table (ino %llu)\n",
+				be32_to_cpu(cfthdr->cft_magic), mp->m_sb.sb_cftino);
+		goto bad_out;
+	}
+	if (be32_to_cpu(cfthdr->cft_flags) > XFS_CFT_FLAG_MAX) {
+		if (!sflag)
+			dbprintf("invalid flags (0x%x) in casefold table (ino %llu)\n",
+				be32_to_cpu(cfthdr->cft_flags), mp->m_sb.sb_cftino);
+		goto bad_out;
+	}
+	if (platform_uuid_compare(&cfthdr->cft_uuid, &mp->m_sb.sb_uuid) != 0) {
+		if (!sflag)
+			dbprintf("mismatched UUID in casefold table (ino %llu)\n",
+				mp->m_sb.sb_cftino);
+		goto bad_out;
+	}
+	ntables = be32_to_cpu(cfthdr->cft_num_tables);
+	if (ntables < XFS_CFT_MIN_NUM_TABLES ||
+			ntables > XFS_CFT_MAX_NUM_TABLES) {
+		if (!sflag)
+			dbprintf("invalid number of tables (%d) in casefold "
+				"table (ino %llu)\n", ntables, mp->m_sb.sb_cftino);
+		goto bad_out;
+	}
+	lower_off = sizeof(xfs_dcft_t) + sizeof(__be32) * (ntables - 1);
+	for (i = 0; i < ntables; i++) {
+		off = be32_to_cpu(cfthdr->cft_table_offset[i]);
+		if (off < lower_off || off > dip->di_core.di_size) {
+			if (!sflag)
+				dbprintf("invalid table offset (%d) in "
+					"casefold table (ino %llu)\n",
+					off, mp->m_sb.sb_cftino);
+			goto bad_out;
+		}
+		lower_off = off + sizeof(__be16);
+	}
+	if (xfs_unicode_read_cft(mp) == 0) {
+		xfree(cfthdr);
+		if (blkmap)
+			blkmap_free(blkmap);
+		return;
+	}
+
+bad_out:
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		mp->m_dirnameops = &xfs_default_nameops;
+		mp->m_attrnameops = &xfs_default_nameops;
+	}
+	error++;
+	xfree(cfthdr);
+	if (blkmap)
+		blkmap_free(blkmap);
+}
+
+static void
 check_dbmap(
 	xfs_agnumber_t	agno,
 	xfs_agblock_t	agbno,
@@ -1605,12 +1772,19 @@
 
 static void
 dir_hash_add(
-	xfs_dahash_t		hash,
+	const uchar_t		*name,
+	int			namelen,
 	xfs_dir2_dataptr_t	addr)
 {
+	xfs_inode_t		inode;
+	xfs_dahash_t		hash;
 	int			i;
 	dirhash_t		*p;
 
+	/* xfs_dir_hashname only uses i_mount in xfs_inode_t for now */
+	inode.i_mount = mp;
+	hash = xfs_dir_hashname(&inode, name, namelen);
+
 	i = DIR_HASH_FUNC(hash, addr);
 	p = malloc(sizeof(*p));
 	p->next = dirhash[i];
@@ -1778,6 +1952,18 @@
 		sumfile = xcalloc(mp->m_rsumsize, 1);
 		sumcompute = xcalloc(mp->m_rsumsize, 1);
 	}
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		if (mp->m_sb.sb_cftino == 0 || mp->m_sb.sb_cftino == NULLFSINO)
+			dbprintf("missing casefold table inode number for "
+				"unicode filesystem\n");
+		else
+			check_cft(); /* need CFT before processing root dir */
+	} else {
+		if (mp->m_sb.sb_cftino != 0 && mp->m_sb.sb_cftino != NULLFSINO)
+			dbprintf("bad casefold table inode number %llu for "
+				"non-unicode filesystem\n", mp->m_sb.sb_cftino);
+	}
+
 	nflag = sflag = tflag = verbose = optind = 0;
 	while ((c = getopt(argc, argv, "b:i:npstv")) != EOF) {
 		switch (c) {
@@ -2188,7 +2374,6 @@
 	char			*endptr;
 	int			freeseen;
 	freetab_t		*freetab;
-	xfs_dahash_t		hash;
 	int			i;
 	int			lastfree;
 	int			lastfree_err;
@@ -2308,8 +2493,18 @@
 		tag_err += INT_GET(*tagp, ARCH_CONVERT) != (char *)dep - (char *)data;
 		addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, db,
 			(char *)dep - (char *)data);
-		hash = libxfs_da_hashname((uchar_t *)dep->name, dep->namelen);
-		dir_hash_add(hash, addr);
+		if (xfs_sb_version_hasunicode(&mp->m_sb) &&
+				xfs_unicode_validate((uchar_t *)dep->name,
+					dep->namelen) != 0) {
+			if (!sflag)
+				dbprintf("dir %lld block %d invalid UTF-8 "
+					"name in entry at %d\n",
+					id->ino, dabno,
+					(int)((char *)dep - (char *)data));
+			error++;
+			break;
+		}
+		dir_hash_add((uchar_t *)dep->name, dep->namelen, addr);
 		ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
 		count++;
 		lastfree = 0;
@@ -2744,6 +2939,10 @@
 			type = DBM_RTSUM;
 			blkmap = blkmap_alloc(dic->di_nextents);
 			addlink_inode(id);
+		} else if (id->ino == mp->m_sb.sb_cftino) {
+			type = DBM_CFT;
+			blkmap = blkmap_alloc(dic->di_nextents);
+			addlink_inode(id);
 		}
 		else if (id->ino == mp->m_sb.sb_uquotino ||
 			 id->ino == mp->m_sb.sb_gquotino) {
@@ -2776,8 +2975,9 @@
 			&nextents, &blkmap, XFS_DATA_FORK);
 		break;
 	case XFS_DINODE_FMT_EXTENTS:
-		process_exinode(id, dip, type, &totdblocks, &totiblocks,
-			&nextents, &blkmap, XFS_DATA_FORK);
+		if (type != DBM_CFT)
+			process_exinode(id, dip, type, &totdblocks, &totiblocks,
+				&nextents, &blkmap, XFS_DATA_FORK);
 		break;
 	case XFS_DINODE_FMT_BTREE:
 		process_btinode(id, dip, type, &totdblocks, &totiblocks,
@@ -2801,6 +3001,8 @@
 			break;
 		}
 	}
+	if (type == DBM_CFT)
+		return;  /* already checked enough in check_cft from init */
 	if (qgdo || qpdo || qudo) {
 		switch (type) {
 		case DBM_DATA:
@@ -2854,6 +3056,7 @@
 		process_rtbitmap(blkmap);
 	else if (type == DBM_RTSUM)
 		process_rtsummary(blkmap);
+
 	/*
 	 * If the CHKD flag is not set, this can legitimately contain garbage;
 	 * xfs_repair may have cleared that bit.
@@ -3634,6 +3837,15 @@
 		lino = XFS_DIR2_SF_GET_INUMBER(sf, XFS_DIR2_SF_INUMBERP(sfe));
 		if (lino > XFS_DIR2_MAX_SHORT_INUM)
 			i8++;
+		if (xfs_sb_version_hasunicode(&mp->m_sb) &&
+				xfs_unicode_validate((uchar_t *)sfe->name,
+					sfe->namelen) != 0) {
+			if (!sflag)
+				dbprintf("dir %lld invalid UTF-8 name in "
+					"entry at offset %d\n",
+					id->ino, XFS_DIR2_SF_GET_OFFSET(sfe));
+			error++;
+		}
 		cid = find_inode(lino, 1);
 		if (cid == NULL) {
 			if (!sflag)
Index: ci/xfsprogs/repair/dino_chunks.c
===================================================================
--- ci.orig/xfsprogs/repair/dino_chunks.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/repair/dino_chunks.c	2008-01-18 15:00:09.080564844 +1100
@@ -885,6 +885,21 @@
 						XFS_AGINO_TO_INO(mp, agno,
 						agino));
 				}
+			} else if (mp->m_sb.sb_cftino ==
+					XFS_AGINO_TO_INO(mp, agno, agino)) {
+				mp->m_sb.sb_cftino = 0;
+
+				if (!no_modify)  {
+					do_warn(_("cleared case fold table "
+						  "inode %llu\n"),
+						XFS_AGINO_TO_INO(mp, agno,
+						agino));
+				} else  {
+					do_warn(_("would clear case fold table"
+						  " inode %llu\n"),
+						XFS_AGINO_TO_INO(mp, agno,
+						agino));
+				}
 			} else if (!no_modify)  {
 				do_warn(_("cleared inode %llu\n"),
 					XFS_AGINO_TO_INO(mp, agno, agino));
Index: ci/xfsprogs/repair/phase2.c
===================================================================
--- ci.orig/xfsprogs/repair/phase2.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/repair/phase2.c	2008-01-18 15:00:09.080564844 +1100
@@ -168,8 +168,15 @@
 				(xfs_agino_t) mp->m_sb.sb_rootino);
 		set_inode_used(ino_rec, 1);
 		set_inode_used(ino_rec, 2);
+		j = 3;
+		/* if using unicode filenames, mark the next inode too */
+		if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+			ASSERT(mp->m_sb.sb_cftino == mp->m_sb.sb_rootino + 3);
+			set_inode_used(ino_rec, 3);
+			j++;
+		}
 
-		for (j = 3; j < XFS_INODES_PER_CHUNK; j++)
+		for (; j < XFS_INODES_PER_CHUNK; j++)
 			set_inode_free(ino_rec, j);
 
 		/*
@@ -212,5 +219,15 @@
 			else
 				do_warn(_("would correct\n"));
 		}
+
+		if (xfs_sb_version_hasunicode(&mp->m_sb) &&
+				is_inode_free(ino_rec, 3)) {
+			do_warn(_("casefold table inode marked free, "));
+			set_inode_used(ino_rec, 3);
+			if (!no_modify)
+				do_warn(_("correcting\n"));
+			else
+				do_warn(_("would correct\n"));
+		}
 	}
 }
Index: ci/xfsprogs/repair/xfs_repair.c
===================================================================
--- ci.orig/xfsprogs/repair/xfs_repair.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/repair/xfs_repair.c	2008-01-18 15:00:09.084564331 +1100
@@ -451,6 +451,26 @@
 		mp->m_sb.sb_rsumino = first_prealloc_ino + 2;
 	}
 
+	if (xfs_sb_version_hasunicode(&mp->m_sb) &&
+			mp->m_sb.sb_cftino != first_prealloc_ino + 3) {
+		do_warn(_("sb casefold table inode %llu %sinconsistent with "
+			"calculated value %lu\n"), mp->m_sb.sb_cftino,
+			(mp->m_sb.sb_cftino == NULLFSINO ? "(NULLFSINO) ":""),
+			first_prealloc_ino + 3);
+
+		if (!no_modify)
+			do_warn(_("resetting superblock casefold table ino "
+				"pointer to %lu\n"), first_prealloc_ino + 3);
+		else
+			do_warn(_("would reset superblock realtime summary ino "
+				"pointer to %lu\n"), first_prealloc_ino + 3);
+
+		/*
+		 * just set the value -- safe since the superblock
+		 * doesn't get flushed out if no_modify is set
+		 */
+		mp->m_sb.sb_cftino = first_prealloc_ino + 3;
+	}
 }
 
 int
Index: ci/xfsprogs/repair/dinode.c
===================================================================
--- ci.orig/xfsprogs/repair/dinode.c	2008-01-18 14:57:36.000000000 +1100
+++ ci/xfsprogs/repair/dinode.c	2008-01-18 15:00:09.088563817 +1100
@@ -17,6 +17,7 @@
  */
 
 #include <libxfs.h>
+#include <casefoldtable.h>
 #include "avl.h"
 #include "globals.h"
 #include "agheader.h"
@@ -1670,6 +1671,100 @@
 }
 
 /*
+ * make sure the header of the case folding table is valid
+ */
+static int
+process_cft(
+	xfs_mount_t	*mp,
+	xfs_ino_t	lino,
+	xfs_dinode_t	*dino,
+	blkmap_t	*blkmap)
+{
+	int		rval = 1;
+	xfs_dcft_t	*cft;
+	int		size;
+	int		off;
+	int		i;
+	xfs_dfsbno_t	fsbno;
+	xfs_buf_t	*bp;
+	int		ntables;
+	int		lower_off;
+
+	/*
+	 * Already confirmed it's in extents, read all the blocks and
+	 * verify the header. Without CRCs, cannot verify the actual
+	 * table. If we find anything invalid, just junk it now and
+	 * it will be rebuilt later in Phase 6.
+	 */
+
+	cft = malloc(sizeof(xfs_dcft_t) + sizeof(__be32) *
+			XFS_CFT_MAX_NUM_TABLES);
+	if (!cft)
+		do_error(_("cannot allocate memory for CFT header\n"));
+
+	/* make sure we can read the entire table */
+	size = (int)be64_to_cpu(dino->di_core.di_size);
+	off = i = 0;
+	while (off < size) {
+		fsbno = blkmap_get(blkmap, i);
+		if (fsbno != NULLDFSBNO)
+			bp = libxfs_readbuf(mp->m_dev,
+					XFS_FSB_TO_DADDR(mp, fsbno),
+					XFS_FSB_TO_BB(mp, 1), 0);
+		if (!bp || fsbno == NULLDFSBNO) {
+			do_warn(_("cannot read casefold table inode %llu, "
+					"disk block %llu\n"), lino, fsbno);
+			goto bad_out;
+		}
+		if (i == 0)
+			memcpy(cft, XFS_BUF_PTR(bp), sizeof(xfs_dcft_t) +
+				sizeof(__be32) * XFS_CFT_MAX_NUM_TABLES);
+		off += XFS_BUF_SIZE(bp);
+		libxfs_putbuf(bp);
+		libxfs_purgebuf(bp);
+		i++;
+	}
+
+	/* verify contents of the header */
+	if (be32_to_cpu(cft->cft_magic) != XFS_CFT_MAGIC) {
+		do_warn(_("bad magic number 0x%x in casefold table (ino %llu)\n"),
+				be32_to_cpu(cft->cft_magic), lino);
+		goto bad_out;
+	}
+	if (be32_to_cpu(cft->cft_flags) > XFS_CFT_FLAG_MAX) {
+		do_warn(_("invalid flags (0x%x) in casefold table (ino %llu)\n"),
+				be32_to_cpu(cft->cft_flags), lino);
+		goto bad_out;
+	}
+	if (platform_uuid_compare(&cft->cft_uuid, &mp->m_sb.sb_uuid) != 0) {
+		do_warn(_("mismatched UUID in casefold table (ino %llu)\n"),
+				lino);
+		goto bad_out;
+	}
+	ntables = be32_to_cpu(cft->cft_num_tables);
+	if (ntables < XFS_CFT_MIN_NUM_TABLES ||
+			ntables > XFS_CFT_MAX_NUM_TABLES) {
+		do_warn(_("invalid number of tables (%d) in casefold table "
+				"(ino %llu)\n"), ntables, lino);
+		goto bad_out;
+	}
+	lower_off = sizeof(xfs_dcft_t) + sizeof(__be32) * (ntables - 1);
+	for (i = 0; i < ntables; i++) {
+		off = be32_to_cpu(cft->cft_table_offset[i]);
+		if (off < lower_off || off > size) {
+			do_warn(_("invalid table offset (%d) in casefold table "
+					"(ino %llu)\n"), off, lino);
+			goto bad_out;
+		}
+		lower_off = off + sizeof(__be16);
+	}
+	rval = 0;
+bad_out:
+	free(cft);
+	return rval;
+}
+
+/*
  * called to process the set of misc inode special inode types
  * that have no associated data storage (fifos, pipes, devices, etc.).
  */
@@ -1903,6 +1998,16 @@
 		}
 		return 0;
 	}
+	if (lino == mp->m_sb.sb_cftino) {
+		if (*type != XR_INO_DATA) {
+			do_warn(_("casefold table inode %llu has bad type 0x%x\n"),
+				lino, dinode_fmt(dinoc));
+			mp->m_sb.sb_cftino = NULLFSINO;
+			return 1;
+		}
+		*type = XR_INO_CFT;
+		return 0;
+	}
 	return 0;
 }
 
@@ -2770,6 +2875,13 @@
 			goto clear_bad_out;
 		}
 		break;
+	case XR_INO_CFT:
+		if (process_cft(mp, lino, dino, dblkmap) != 0) {
+			do_warn(_("problem with casefold table in inode %llu\n"),
+				lino);
+			goto clear_bad_out;
+		}
+		break;
 	default:
 		break;
 	}
Index: ci/xfsprogs/db/Makefile
===================================================================
--- ci.orig/xfsprogs/db/Makefile	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/db/Makefile	2008-01-18 15:00:09.088563817 +1100
@@ -8,7 +8,7 @@
 LTCOMMAND = xfs_db
 
 HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \
-	bmapbt.h bmroot.h bnobt.h check.h cntbt.h command.h convert.h \
+	bmapbt.h bmroot.h bnobt.h cft.h check.h cntbt.h command.h convert.h \
 	dbread.h debug.h dir.h dir2.h dir2sf.h dirshort.h dquot.h echo.h \
 	faddr.h field.h flist.h fprint.h frag.h freesp.h hash.h help.h \
 	init.h inobt.h inode.h input.h io.h malloc.h metadump.h output.h \
Index: ci/xfsprogs/db/command.c
===================================================================
--- ci.orig/xfsprogs/db/command.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/db/command.c	2008-01-18 15:00:09.088563817 +1100
@@ -33,6 +33,7 @@
 #include "agf.h"
 #include "agfl.h"
 #include "agi.h"
+#include "cft.h"
 #include "frag.h"
 #include "freesp.h"
 #include "help.h"
@@ -121,6 +122,7 @@
 	attrset_init();
 	block_init();
 	bmap_init();
+	cft_init();
 	check_init();
 	convert_init();
 	debug_init();
Index: ci/xfsprogs/db/field.c
===================================================================
--- ci.orig/xfsprogs/db/field.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/db/field.c	2008-01-18 15:00:09.092563304 +1100
@@ -39,6 +39,7 @@
 #include "dquot.h"
 #include "dir2.h"
 #include "dir2sf.h"
+#include "cft.h"
 
 const ftattr_t	ftattrtab[] = {
 	{ FLDT_AEXTNUM, "aextnum", fp_num, "%d", SI(bitsz(xfs_aextnum_t)),
@@ -133,6 +134,8 @@
 	  0, fa_cfileoffd, NULL },
 	{ FLDT_CFSBLOCK, "cfsblock", fp_num, "%llu", SI(BMBT_STARTBLOCK_BITLEN),
 	  0, fa_cfsblock, NULL },
+	{ FLDT_CFT, "cft", NULL, (char *)cft_flds, cft_size, FTARG_SIZE, NULL,
+	  cft_flds },
 	{ FLDT_CHARNS, "charns", fp_charns, NULL, SI(bitsz(char)), 0, NULL,
 	  NULL },
 	{ FLDT_CHARS, "chars", fp_num, "%c", SI(bitsz(char)), 0, NULL, NULL },
Index: ci/xfsprogs/db/field.h
===================================================================
--- ci.orig/xfsprogs/db/field.h	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/db/field.h	2008-01-18 15:00:09.092563304 +1100
@@ -61,6 +61,7 @@
 	FLDT_CFILEOFFA,
 	FLDT_CFILEOFFD,
 	FLDT_CFSBLOCK,
+	FLDT_CFT,
 	FLDT_CHARNS,
 	FLDT_CHARS,
 	FLDT_CNTBT,
Index: ci/xfsprogs/db/inode.c
===================================================================
--- ci.orig/xfsprogs/db/inode.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/db/inode.c	2008-01-18 15:00:09.092563304 +1100
@@ -410,6 +410,8 @@
 		else if (iocur_top->ino == mp->m_sb.sb_uquotino ||
 			 iocur_top->ino == mp->m_sb.sb_gquotino)
 			return TYP_DQBLK;
+		else if (iocur_top->ino == mp->m_sb.sb_cftino)
+			return TYP_CFT;
 		else
 			return TYP_DATA;
 	default:
Index: ci/xfsprogs/db/metadump.c
===================================================================
--- ci.orig/xfsprogs/db/metadump.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/db/metadump.c	2008-01-18 15:00:09.096562791 +1100
@@ -1537,6 +1537,9 @@
 	if (!copy_ino(mp->m_sb.sb_rsumino, TYP_RTSUMMARY))
 		return 0;
 
+	if (!copy_ino(mp->m_sb.sb_cftino, TYP_CFT))
+		return 0;
+
 	if (!copy_ino(mp->m_sb.sb_uquotino, TYP_DQBLK))
 		return 0;
 
Index: ci/xfsprogs/db/sb.c
===================================================================
--- ci.orig/xfsprogs/db/sb.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/db/sb.c	2008-01-18 15:00:09.096562791 +1100
@@ -108,6 +108,7 @@
 	{ "logsectsize", FLDT_UINT16D, OI(OFF(logsectsize)), C1, 0, TYP_NONE },
 	{ "logsunit", FLDT_UINT32D, OI(OFF(logsunit)), C1, 0, TYP_NONE },
 	{ "features2", FLDT_UINT32X, OI(OFF(features2)), C1, 0, TYP_NONE },
+	{ "cftino", FLDT_INO, OI(OFF(cftino)), C1, 0, TYP_INODE },
 	{ NULL }
 };
 
@@ -604,12 +605,16 @@
 		strcat(s, ",EXTFLG");
 	if (XFS_SB_VERSION_HASSECTOR(sbp))
 		strcat(s, ",SECTOR");
+	if (xfs_sb_version_hasoldci(sbp))
+		strcat(s, ",OLDCI");
 	if (XFS_SB_VERSION_HASMOREBITS(sbp))
 		strcat(s, ",MOREBITS");
 	if (XFS_SB_VERSION_HASATTR2(sbp))
 		strcat(s, ",ATTR2");
 	if (XFS_SB_VERSION_LAZYSBCOUNT(sbp))
 		strcat(s, ",LAZYSBCOUNT");
+	if (xfs_sb_version_hasunicode(sbp))
+		strcat(s, ",UNICODE");
 	return s;
 }
 
Index: ci/xfsprogs/db/type.c
===================================================================
--- ci.orig/xfsprogs/db/type.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/db/type.c	2008-01-18 15:00:09.096562791 +1100
@@ -43,6 +43,7 @@
 #include "dquot.h"
 #include "dir2.h"
 #include "text.h"
+#include "cft.h"
 
 static const typ_t	*findtyp(char *name);
 static int		type_f(int argc, char **argv);
@@ -61,6 +62,7 @@
 	{ TYP_BMAPBTA, "bmapbta", handle_struct, bmapbta_hfld },
 	{ TYP_BMAPBTD, "bmapbtd", handle_struct, bmapbtd_hfld },
 	{ TYP_BNOBT, "bnobt", handle_struct, bnobt_hfld },
+	{ TYP_CFT, "cft", handle_struct, cft_hfld },
 	{ TYP_CNTBT, "cntbt", handle_struct, cntbt_hfld },
 	{ TYP_DATA, "data", handle_block, NULL },
 	{ TYP_DIR, "dir", handle_struct, dir_hfld },
Index: ci/xfsprogs/db/type.h
===================================================================
--- ci.orig/xfsprogs/db/type.h	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/db/type.h	2008-01-18 15:00:09.096562791 +1100
@@ -24,7 +24,7 @@
 typedef enum typnm
 {
 	TYP_AGF, TYP_AGFL, TYP_AGI, TYP_ATTR, TYP_BMAPBTA,
-	TYP_BMAPBTD, TYP_BNOBT, TYP_CNTBT, TYP_DATA, TYP_DIR,
+	TYP_BMAPBTD, TYP_BNOBT, TYP_CFT, TYP_CNTBT, TYP_DATA, TYP_DIR,
 	TYP_DIR2, TYP_DQBLK, TYP_INOBT, TYP_INODATA, TYP_INODE,
 	TYP_LOG, TYP_RTBITMAP, TYP_RTSUMMARY, TYP_SB, TYP_SYMLINK,
 	TYP_TEXT, TYP_NONE
Index: ci/xfsprogs/include/libxfs.h
===================================================================
--- ci.orig/xfsprogs/include/libxfs.h	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/include/libxfs.h	2008-01-18 15:00:09.112560739 +1100
@@ -22,7 +22,7 @@
 #define XFS_BIG_BLKNOS	1
 
 #include <xfs/platform_defs.h>
-
+#include <ctype.h>
 #include <pthread.h>
 #include <xfs/list.h>
 #include <xfs/cache.h>
@@ -50,6 +50,7 @@
 #include <xfs/xfs_alloc.h>
 #include <xfs/xfs_btree.h>
 #include <xfs/xfs_bmap.h>
+#include <xfs/xfs_unicode.h>
 
 
 #ifndef XFS_SUPER_MAGIC
@@ -175,6 +176,9 @@
 	int			m_attr_magicpct;/* 37% of the blocksize */
 	int			m_dir_magicpct;	/* 37% of the dir blocksize */
 	__uint8_t		m_dirversion;	/* 1 or 2 */
+	const struct xfs_nameops *m_dirnameops;	/* vector of dir name ops */
+	const struct xfs_nameops *m_attrnameops;/* vector of attr name ops */
+	const 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 */
@@ -401,7 +405,6 @@
 extern void	libxfs_free (void *);
 extern void	*libxfs_realloc (void *, size_t);
 
-
 /*
  * Inode interface
  */
@@ -525,6 +528,10 @@
  * All other routines we want to keep common...
  */
 
+extern const struct xfs_nameops xfs_default_nameops;
+extern const struct xfs_nameops xfs_unicode_nameops;
+extern const struct xfs_nameops xfs_unicode_ci_nameops;
+
 extern int	libxfs_highbit32 (__uint32_t);
 extern int	libxfs_highbit64 (__uint64_t);
 extern uint	libxfs_da_log2_roundup (uint);
@@ -556,6 +563,7 @@
 				xfs_extlen_t);
 
 /* Directory/Attribute routines used by xfs_repair */
+extern void	libxfs_attr_mount(xfs_mount_t *);
 extern void	libxfs_da_bjoin (xfs_trans_t *, xfs_dabuf_t *);
 extern int	libxfs_da_shrink_inode (xfs_da_args_t *, xfs_dablk_t,
 				xfs_dabuf_t *);
Index: ci/xfsprogs/include/xfs_attr_leaf.h
===================================================================
--- ci.orig/xfsprogs/include/xfs_attr_leaf.h	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/include/xfs_attr_leaf.h	2008-01-18 15:00:09.116560225 +1100
@@ -36,6 +36,7 @@
 struct xfs_da_state;
 struct xfs_da_state_blk;
 struct xfs_inode;
+struct xfs_mount;
 struct xfs_trans;
 
 /*========================================================================
@@ -192,6 +193,12 @@
 	return (((bsize) >> 1) + ((bsize) >> 2));
 }
 
+/*
+ * Do hash based on nameops
+ */
+#define xfs_attr_hashname(dp, n, l) \
+		((dp)->i_mount->m_attrnameops->hashname((dp), (n), (l)))
+
 
 /*========================================================================
  * Structure used to pass context around among the routines.
@@ -274,6 +281,7 @@
 /*
  * Utility routines.
  */
+void	xfs_attr_mount(struct xfs_mount *mp);
 xfs_dahash_t	xfs_attr_leaf_lasthash(struct xfs_dabuf *bp, int *count);
 int	xfs_attr_leaf_order(struct xfs_dabuf *leaf1_bp,
 				   struct xfs_dabuf *leaf2_bp);
Index: ci/xfsprogs/include/xfs_da_btree.h
===================================================================
--- ci.orig/xfsprogs/include/xfs_da_btree.h	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/include/xfs_da_btree.h	2008-01-18 15:00:09.124559199 +1100
@@ -103,6 +103,15 @@
  *========================================================================*/
 
 /*
+ * Search comparison results
+ */
+typedef enum {
+	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_dacmp_t;
+
+/*
  * Structure to ease passing around component names.
  */
 typedef struct xfs_da_args {
@@ -205,12 +214,37 @@
 		(uint)(XFS_DA_LOGOFF(BASE, ADDR)), \
 		(uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1)
 
+/*
+ * Name ops for directory and/or attr name operations
+ */
+
+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;
+	xfs_compname_t		compname;
+} xfs_nameops_t;
+
 
 #ifdef __KERNEL__
 /*========================================================================
  * Function prototypes for the kernel.
  *========================================================================*/
 
+extern const struct xfs_nameops xfs_default_nameops;
+extern const struct xfs_nameops xfs_unicode_nameops;
+extern const struct xfs_nameops xfs_unicode_ci_nameops;
+
+xfs_dacmp_t xfs_default_compname(struct xfs_inode *inode, const uchar_t *name1,
+				int len1, const uchar_t *name2, int len2);
+
+int	xfs_da_setup_name_and_hash(xfs_da_args_t *args, const uchar_t *name,
+				int namelen);
+void	xfs_da_cleanup_name(xfs_da_args_t *args, const uchar_t *name);
+
 /*
  * Routines used for growing the Btree.
  */
Index: ci/xfsprogs/include/xfs_dir2.h
===================================================================
--- ci.orig/xfsprogs/include/xfs_dir2.h	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/include/xfs_dir2.h	2008-01-18 15:00:09.124559199 +1100
@@ -72,6 +72,13 @@
 	struct uio	*uio;		/* uio control structure */
 } xfs_dir2_put_args_t;
 
+#define xfs_dir_hashname(dp, 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((dp), (n1), (l1), \
+							(n2), (l2)))
+
 /*
  * Other interfaces used by the rest of the dir v2 code.
  */
Index: ci/xfsprogs/include/xfs_unicode.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ci/xfsprogs/include/xfs_unicode.h	2008-01-18 15:00:09.128558686 +1100
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007 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			cft_magic;	/* validity check */
+	__be32			cft_flags;
+	uuid_t			cft_uuid;	/* UUID of the filesystem */
+	__be32			cft_crc;	/* for future support */
+	__be32			cft_num_tables;	/* single, double, etc */
+	__be32			cft_table_offset[1];
+} xfs_dcft_t;
+
+/*
+ * Case Fold Table - in core version. Must match the ondisk version above.
+ */
+typedef struct xfs_cft {
+	__uint32_t		cft_magic;
+	__uint32_t		cft_flags;
+	uuid_t			cft_uuid;	/* UUID of the filesystem */
+	__uint32_t		cft_crc;
+	__uint32_t		cft_num_tables;	/* single, double, etc */
+	__uint32_t		cft_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)->cft_table_offset[n])
+#define XFS_DCFT_PTR(t,n)	(__be16 *)(((char *)(t)) + \
+					be32_to_cpu((t)->cft_table_offset[n]))
+
+__uint32_t xfs_unicode_hash(const xfs_cft_t *cft,
+				const uchar_t *name, int namelen);
+
+int xfs_unicode_casecmp(const xfs_cft_t *cft, const uchar_t *name1,
+				int len1, const uchar_t *name2, int len2);
+
+char *xfs_alloc_unicode_nls_name(void);
+void xfs_free_unicode_nls_name(char *name);
+
+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);
+
+#endif /* __XFS_UNICODE_H__ */
Index: ci/xfsprogs/libxfs/init.c
===================================================================
--- ci.orig/xfsprogs/libxfs/init.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/libxfs/init.c	2008-01-18 15:00:09.136557660 +1100
@@ -579,10 +579,14 @@
 	else
 		libxfs_dir_mount(mp);
 
-	/* Initialize cached values for the attribute manager */
-	mp->m_attr_magicpct = (mp->m_sb.sb_blocksize * 37) / 100;
+	/*
+	 * Initialize the attribute manager's entries.
+	 */
+	libxfs_attr_mount(mp);
 
-	/* Initialize the precomputed transaction reservations values */
+	/*
+	 * Initialize the precomputed transaction reservations values.
+	 */
 	libxfs_trans_init(mp);
 
 	if (dev == 0)	/* maxtrres, we have no device so leave now */
Index: ci/xfsprogs/libxfs/xfs.h
===================================================================
--- ci.orig/xfsprogs/libxfs/xfs.h	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/libxfs/xfs.h	2008-01-18 15:00:09.136557660 +1100
@@ -95,6 +95,8 @@
 #define xfs_itobp			libxfs_itobp
 #define xfs_iformat			libxfs_iformat
 #define xfs_ichgtime			libxfs_ichgtime
+#define xfs_iget(m,t,i,f,lf,ip,b)	libxfs_iget(m,t,i,lf,ip,b)
+#define xfs_iput			libxfs_iput
 #define xfs_bmapi			libxfs_bmapi
 #define xfs_bmapi_single		libxfs_bmapi_single
 #define xfs_bmap_finish			libxfs_bmap_finish
@@ -146,6 +148,7 @@
 #define xfs_dir2_data_freescan		libxfs_dir2_data_freescan
 #define xfs_dir2_free_log_bests		libxfs_dir2_free_log_bests
 
+#define xfs_attr_mount			libxfs_attr_mount
 #define xfs_attr_leaf_newentsize	libxfs_attr_leaf_newentsize
 #define xfs_attr_set_int		libxfs_attr_set_int
 #define xfs_attr_remove_int		libxfs_attr_remove_int
@@ -175,7 +178,7 @@
 #define xfs_validate_extents(e,n,d,f)	((void) 0)	/* debug only */
 #define xfs_buf_relse(bp)		libxfs_putbuf(bp)
 #define xfs_read_buf(mp,devp,blkno,len,f,bpp)	\
-	( *(bpp) = libxfs_readbuf( *(dev_t*)devp, (blkno), (len), 1), 0 )
+	( *(bpp) = libxfs_readbuf((devp), (blkno), (len), 1), 0 )
 #define xfs_buf_get_flags(devp,blkno,len,f)	\
 	( libxfs_getbuf( devp, (blkno), (len) ) )
 #define xfs_bwrite(mp,bp)		libxfs_writebuf((bp), 0)
@@ -205,10 +208,13 @@
 #define kmem_zone_alloc(z, f)	libxfs_zone_zalloc(z)
 #define kmem_zone_zalloc(z, f)	libxfs_zone_zalloc(z)
 #define kmem_zone_free(z, p)	libxfs_zone_free(z, p)
+#define kmem_zone_destroy(z)	((void) 0)
 #define kmem_realloc(p,sz,u,f)	libxfs_realloc(p,sz)
 #define kmem_zalloc(size, f)	libxfs_malloc(size)
 #define kmem_alloc(size, f)	libxfs_malloc(size)
 #define kmem_free(p, size)	libxfs_free(p)
+#define vmalloc(size)		libxfs_malloc(size)
+#define vfree(p)		libxfs_free(p)
 
 /* directory management */
 #define xfs_dir2_trace_args(where, args)		((void) 0)
@@ -288,6 +294,8 @@
 #define XFS_MOUNT_32BITINODES		LIBXFS_MOUNT_32BITINODES
 #define XFS_MOUNT_32BITINOOPT		LIBXFS_MOUNT_32BITINOOPT
 #define XFS_MOUNT_COMPAT_ATTR		LIBXFS_MOUNT_COMPAT_ATTR
+#define XFS_MOUNT_CI_LOOKUP		0	/* ignored in userspace */
+#define XFS_MOUNT_CI_ATTR		0	/* ignored in userspace */
 #define XFS_ILOCK_EXCL			0
 #define xfs_sort			qsort
 #define down_read(a)			((void) 0)
@@ -300,6 +308,10 @@
 #define spinlock_init(a,b)		((void) 0)
 #define spin_lock(a)			((void) 0)
 #define spin_unlock(a)			((void) 0)
+#define mutex_t				int
+#define mutex_init(a)			((void) 0)
+#define mutex_lock(a)			((void) 0)
+#define mutex_unlock(a)			((void) 0)
 #define xfs_btree_reada_bufl(m,fsb,c)	((void) 0)
 #define xfs_btree_reada_bufs(m,fsb,c,x)	((void) 0)
 #define XFS_SB_LOCK(mp)			0
@@ -559,6 +571,10 @@
 			xfs_alloc_key_t *, xfs_btree_cur_t **, int *);
 
 /* xfs_da_btree.c */
+xfs_dacmp_t xfs_default_compname(struct xfs_inode *, const uchar_t *, int,
+			const uchar_t *, int);
+int  xfs_da_setup_name_and_hash(xfs_da_args_t *, const uchar_t *, int);
+void xfs_da_cleanup_name(xfs_da_args_t *, const uchar_t *);
 xfs_dabuf_t *xfs_da_buf_make (int, xfs_buf_t **, inst_t *);
 void xfs_da_binval (struct xfs_trans *, xfs_dabuf_t *);
 void xfs_da_buf_done (xfs_dabuf_t *);
@@ -678,6 +694,8 @@
 void xfs_trans_mod_sb (xfs_trans_t *, uint, long);
 int  xfs_trans_unlock_chunk (xfs_log_item_chunk_t *, int, int, xfs_lsn_t);
 
+int  utf8_mbtowc(wchar_t *p, const __u8 *s, int n);
+int  utf8_wctomb(__u8 *s, wchar_t wc, int maxlen);
 
 #ifndef DEBUG
 #define xfs_inobp_check(mp,bp)				((void) 0)
Index: ci/xfsprogs/libxfs/xfs_attr.c
===================================================================
--- ci.orig/xfsprogs/libxfs/xfs_attr.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/libxfs/xfs_attr.c	2008-01-18 15:00:09.144556633 +1100
@@ -64,6 +64,17 @@
  * Overall external interface routines.
  *========================================================================*/
 
+void
+xfs_attr_mount(struct xfs_mount *mp)
+{
+	mp->m_attr_magicpct = (mp->m_sb.sb_blocksize * 37) / 100;
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		mp->m_attrnameops = (mp->m_flags & XFS_MOUNT_CI_ATTR) ?
+			&xfs_unicode_ci_nameops : &xfs_unicode_nameops;
+	} else
+		mp->m_attrnameops = &xfs_default_nameops;
+}
+
 int
 xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
 		 char *value, int valuelen, int flags)
@@ -103,18 +114,18 @@
 	 * Fill in the arg structure for this request.
 	 */
 	memset((char *)&args, 0, sizeof(args));
-	args.name = (const uchar_t *)name;
-	args.namelen = namelen;
 	args.value = (uchar_t *)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.addname = 1;
 	args.oknoent = 1;
+	error = xfs_da_setup_name_and_hash(&args, (uchar_t *)name, namelen);
+	if (error)
+		return error;
 
 	nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
 	if (local) {
@@ -159,6 +170,7 @@
 				      0, XFS_TRANS_PERM_LOG_RES,
 				      XFS_ATTRSET_LOG_COUNT))) {
 		xfs_trans_cancel(args.trans, 0);
+		xfs_da_cleanup_name(&args, (uchar_t *)name);
 		return(error);
 	}
 	xfs_ilock(dp, XFS_ILOCK_EXCL);
@@ -169,6 +181,7 @@
 	if (error) {
 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
 		xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
+		xfs_da_cleanup_name(&args, (uchar_t *)name);
 		return (error);
 	}
 
@@ -220,6 +233,7 @@
 			if (!error && (flags & ATTR_KERNOTIME) == 0) {
 				xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
 			}
+			xfs_da_cleanup_name(&args, (uchar_t *)name);
 			return(error == 0 ? err2 : error);
 		}
 
@@ -290,6 +304,7 @@
 		xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
 	}
 
+	xfs_da_cleanup_name(&args, (uchar_t *)name);
 	return(error);
 
 out:
@@ -297,6 +312,7 @@
 		xfs_trans_cancel(args.trans,
 			XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
 	xfs_iunlock(dp, XFS_ILOCK_EXCL);
+	xfs_da_cleanup_name(&args, (uchar_t *)name);
 	return(error);
 }
 
@@ -313,21 +329,23 @@
 	 * Fill in the arg structure for this request.
 	 */
 	memset((char *)&args, 0, sizeof(args));
-	args.name = (const uchar_t *)name;
-	args.namelen = namelen;
 	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;
+	error = xfs_da_setup_name_and_hash(&args, (uchar_t *)name, namelen);
+	if (error)
+		return error;
 
 	/*
 	 * Attach the dquots to the inode.
 	 */
-	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
+	if ((error = XFS_QM_DQATTACH(mp, dp, 0))) {
+		xfs_da_cleanup_name(&args, (uchar_t *)name);
 		return (error);
+	}
 
 	/*
 	 * Start our first transaction of the day.
@@ -355,6 +373,7 @@
 				      0, XFS_TRANS_PERM_LOG_RES,
 				      XFS_ATTRRM_LOG_COUNT))) {
 		xfs_trans_cancel(args.trans, 0);
+		xfs_da_cleanup_name(&args, (uchar_t *)name);
 		return(error);
 	}
 
@@ -413,6 +432,7 @@
 		xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
 	}
 
+	xfs_da_cleanup_name(&args, (uchar_t *)name);
 	return(error);
 
 out:
@@ -420,6 +440,7 @@
 		xfs_trans_cancel(args.trans,
 			XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
 	xfs_iunlock(dp, XFS_ILOCK_EXCL);
+	xfs_da_cleanup_name(&args, (uchar_t *)name);
 	return(error);
 }
 
Index: ci/xfsprogs/libxfs/xfs_attr_leaf.c
===================================================================
--- ci.orig/xfsprogs/libxfs/xfs_attr_leaf.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/libxfs/xfs_attr_leaf.c	2008-01-18 15:00:09.152555607 +1100
@@ -372,18 +372,19 @@
 
 	sfe = &sf->list[0];
 	for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {
-		nargs.name = (const uchar_t *)sfe->nameval;
-		nargs.namelen = sfe->namelen;
 		nargs.value = (uchar_t *)&sfe->nameval[nargs.namelen];
 		nargs.valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
-		nargs.hashval = xfs_da_hashname((const uchar_t *)sfe->nameval,
-						sfe->namelen);
+		error = xfs_da_setup_name_and_hash(&nargs, sfe->nameval,
+				sfe->namelen);
+		if (error)
+			goto out;
 		nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
 				((sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
 		error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */
 		ASSERT(error == ENOATTR);
 		error = xfs_attr_leaf_add(bp, &nargs);
 		ASSERT(error != ENOSPC);
+		xfs_da_cleanup_name(&nargs, sfe->nameval);
 		if (error)
 			goto out;
 		sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
@@ -1684,7 +1685,7 @@
 		else
 			break;
 	}
-	ASSERT((probe >= 0) && 
+	ASSERT((probe >= 0) &&
 	       (!leaf->hdr.count
 	       || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))));
 	ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT)
Index: ci/xfsprogs/libxfs/xfs_da_btree.c
===================================================================
--- ci.orig/xfsprogs/libxfs/xfs_da_btree.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/libxfs/xfs_da_btree.c	2008-01-18 15:00:09.156555094 +1100
@@ -1540,6 +1540,92 @@
 	}
 }
 
+
+static xfs_dahash_t
+xfs_default_hashname(xfs_inode_t *inode, const uchar_t *name, int namelen)
+{
+	return xfs_da_hashname(name, namelen);
+}
+
+xfs_dacmp_t
+xfs_default_compname(xfs_inode_t *inode, 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;
+}
+
+static xfs_dahash_t
+xfs_unicode_ci_hashname(
+	xfs_inode_t	*inode,
+	const uchar_t	*name,
+	int		namelen)
+{
+	return xfs_unicode_hash(inode->i_mount->m_cft, name, namelen);
+}
+
+static xfs_dacmp_t
+xfs_unicode_ci_compname(
+	xfs_inode_t	*inode,
+	const uchar_t	*name1,
+	int		len1,
+	const uchar_t	*name2,
+	int 		len2)
+{
+	if (len1 == len2 && memcmp(name1, name2, len1) == 0)
+		return XFS_CMP_EXACT;
+
+	return xfs_unicode_casecmp(inode->i_mount->m_cft, name1, len1,
+			name2, len2) == 0 ? XFS_CMP_CASE : XFS_CMP_DIFFERENT;
+}
+
+const struct xfs_nameops xfs_default_nameops = {
+	.hashname	= xfs_default_hashname,
+	.compname	= xfs_default_compname
+};
+
+const struct xfs_nameops xfs_unicode_nameops = {
+	.hashname	= xfs_unicode_ci_hashname,
+	.compname	= xfs_default_compname,
+};
+
+const struct xfs_nameops xfs_unicode_ci_nameops = {
+	.hashname	= xfs_unicode_ci_hashname,
+	.compname	= xfs_unicode_ci_compname,
+};
+
+int
+xfs_da_setup_name_and_hash(
+	xfs_da_args_t		*args,
+	const uchar_t 		*name,
+	int			namelen)
+{
+	xfs_mount_t		*mp = args->dp->i_mount;
+
+	/* for libxfs usage, no extended characters should be used */
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		int	rval;
+		rval = xfs_unicode_validate(name, namelen);
+		if (rval < 0)
+			return -rval;
+	}
+	args->name = name;
+	args->namelen = namelen;
+	args->hashval = (args->whichfork == XFS_ATTR_FORK) ?
+		xfs_attr_hashname(args->dp, args->name, args->namelen) :
+		xfs_dir_hashname(args->dp, args->name, args->namelen);
+	return 0;
+}
+
+void
+xfs_da_cleanup_name(
+	xfs_da_args_t		*args,
+	const uchar_t		*name)
+{
+	if (args->name != name)
+		xfs_free_unicode_nls_name((char *)args->name);
+}
+
 /*
  * Add a block to the btree ahead of the file.
  * Return the new block number to the caller.
Index: ci/xfsprogs/libxfs/xfs_dir2.c
===================================================================
--- ci.orig/xfsprogs/libxfs/xfs_dir2.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/libxfs/xfs_dir2.c	2008-01-18 15:00:09.168553554 +1100
@@ -23,6 +23,53 @@
 
 #include <xfs.h>
 
+/*
+ * V1 case-insensitive support for directories
+ */
+static xfs_dahash_t
+xfs_ascii_ci_hashname(
+	xfs_inode_t	*inode,
+	const uchar_t	*name,
+	int		namelen)
+{
+	xfs_dahash_t	hash;
+	int		i;
+
+	for (i = 0, hash = 0; i < namelen; i++)
+		hash = tolower(name[i]) ^ rol32(hash, 7);
+
+	return hash;
+}
+
+static xfs_dacmp_t
+xfs_ascii_ci_compname(
+	xfs_inode_t	*inode,
+	const uchar_t	*name1,
+	int		len1,
+	const uchar_t	*name2,
+	int 		len2)
+{
+	xfs_dacmp_t	result = XFS_CMP_EXACT;
+	int		i;
+
+	if (len1 != len2)
+		return XFS_CMP_DIFFERENT;
+
+	for (i = 0; i < len1; i++) {
+		if (name1[i] == name2[i])
+			continue;
+		if (tolower(name1[i]) != tolower(name2[i]))
+			return XFS_CMP_DIFFERENT;
+		result = XFS_CMP_CASE;
+	}
+
+	return result;
+}
+
+static const struct xfs_nameops xfs_ascii_ci_nameops = {
+	.hashname	= xfs_ascii_ci_hashname,
+	.compname	= xfs_ascii_ci_compname,
+};
 
 /*
  * Initialize directory-related fields in the mount structure.
@@ -46,6 +93,13 @@
 		(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;
+
+	if (xfs_sb_version_hasunicode(&mp->m_sb)) {
+		mp->m_dirnameops = (mp->m_flags & XFS_MOUNT_CI_LOOKUP) ?
+			&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;
 }
 
 /*
@@ -71,21 +125,21 @@
 }
 
 /*
-  Enter a name in a directory.
+ * Enter a name in a directory.
  */
-STATIC int					/* error */
+int
 xfs_dir2_createname(
-	xfs_trans_t		*tp,		/* transaction pointer */
-	xfs_inode_t		*dp,		/* incore directory inode */
-	uchar_t			*name,		/* new entry name */
-	int			namelen,	/* new entry name length */
+	xfs_trans_t		*tp,
+	xfs_inode_t		*dp,
+	uchar_t			*name,
+	int			namelen,
 	xfs_ino_t		inum,		/* new entry inode number */
 	xfs_fsblock_t		*first,		/* bmap's firstblock */
 	xfs_bmap_free_t		*flist,		/* bmap's freeblock list */
 	xfs_extlen_t		total)		/* bmap's total block count */
 {
-	xfs_da_args_t		args;		/* operation arguments */
-	int			rval;		/* return value */
+	xfs_da_args_t		args;
+	int			rval;
 	int			v;		/* type-checking value */
 
 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
@@ -93,12 +147,7 @@
 		return rval;
 	}
 	XFS_STATS_INC(xs_dir_create);
-	/*
-	 * Fill in the arg structure for this request.
-	 */
-	args.name = name;
-	args.namelen = namelen;
-	args.hashval = xfs_da_hashname(name, namelen);
+
 	args.inumber = inum;
 	args.dp = dp;
 	args.firstblock = first;
@@ -108,48 +157,45 @@
 	args.trans = tp;
 	args.justcheck = 0;
 	args.addname = args.oknoent = 1;
-	/*
-	 * Decide on what work routines to call based on the inode size.
-	 */
+	rval = xfs_da_setup_name_and_hash(&args, name, namelen);
+	if (rval)
+		return rval;
+
 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 		rval = xfs_dir2_sf_addname(&args);
-	else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
-		return rval;
-	} else if (v)
+	else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
+		goto out;
+	else if (v)
 		rval = xfs_dir2_block_addname(&args);
-	else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
-		return rval;
-	} else if (v)
+	else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
+		goto out;
+	else if (v)
 		rval = xfs_dir2_leaf_addname(&args);
 	else
 		rval = xfs_dir2_node_addname(&args);
+out:
+	xfs_da_cleanup_name(&args, name);
 	return rval;
 }
 
 /*
  * Lookup a name in a directory, give back the inode number.
  */
-STATIC int				/* error */
+int
 xfs_dir2_lookup(
-	xfs_trans_t	*tp,		/* transaction pointer */
-	xfs_inode_t	*dp,		/* incore directory inode */
-	uchar_t		*name,		/* lookup name */
-	int		namelen,	/* lookup name length */
+	xfs_trans_t	*tp,
+	xfs_inode_t	*dp,
+	uchar_t		*name,
+	int		namelen,
 	xfs_ino_t	*inum)		/* out: inode number */
 {
-	xfs_da_args_t	args;		/* operation arguments */
-	int		rval;		/* return value */
+	xfs_da_args_t	args;
+	int		rval;
 	int		v;		/* type-checking value */
 
 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	XFS_STATS_INC(xs_dir_lookup);
 
-	/*
-	 * Fill in the arg structure for this request.
-	 */
-	args.name = name;
-	args.namelen = namelen;
-	args.hashval = xfs_da_hashname(name, namelen);
 	args.inumber = 0;
 	args.dp = dp;
 	args.firstblock = NULL;
@@ -159,17 +205,20 @@
 	args.trans = tp;
 	args.justcheck = args.addname = 0;
 	args.oknoent = 1;
-	/*
-	 * Decide on what work routines to call based on the inode size.
-	 */
+	args.value = NULL;	/* value may contain actual name on return */
+	args.valuelen = 0;
+	rval = xfs_da_setup_name_and_hash(&args, name, namelen);
+	if (rval)
+		return rval;
+
 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 		rval = xfs_dir2_sf_lookup(&args);
 	else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
-		return rval;
+		goto out;
 	} else if (v)
 		rval = xfs_dir2_block_lookup(&args);
 	else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
-		return rval;
+		goto out;
 	} else if (v)
 		rval = xfs_dir2_leaf_lookup(&args);
 	else
@@ -178,35 +227,32 @@
 		rval = 0;
 	if (rval == 0)
 		*inum = args.inumber;
+out:
+	xfs_da_cleanup_name(&args, name);
 	return rval;
 }
 
 /*
  * Remove an entry from a directory.
  */
-STATIC int				/* error */
+int
 xfs_dir2_removename(
-	xfs_trans_t	*tp,		/* transaction pointer */
-	xfs_inode_t	*dp,		/* incore directory inode */
-	uchar_t		*name,		/* name of entry to remove */
-	int		namelen,	/* name length of entry to remove */
-	xfs_ino_t	ino,		/* inode number of entry to remove */
+	xfs_trans_t	*tp,
+	xfs_inode_t	*dp,
+	uchar_t		*name,
+	int		namelen,
+	xfs_ino_t	ino,
 	xfs_fsblock_t	*first,		/* bmap's firstblock */
 	xfs_bmap_free_t	*flist,		/* bmap's freeblock list */
 	xfs_extlen_t	total)		/* bmap's total block count */
 {
-	xfs_da_args_t	args;		/* operation arguments */
-	int		rval;		/* return value */
+	xfs_da_args_t	args;
+	int		rval;
 	int		v;		/* type-checking value */
 
 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 	XFS_STATS_INC(xs_dir_remove);
-	/*
-	 * Fill in the arg structure for this request.
-	 */
-	args.name = name;
-	args.namelen = namelen;
-	args.hashval = xfs_da_hashname(name, namelen);
+
 	args.inumber = ino;
 	args.dp = dp;
 	args.firstblock = first;
@@ -215,53 +261,50 @@
 	args.whichfork = XFS_DATA_FORK;
 	args.trans = tp;
 	args.justcheck = args.addname = args.oknoent = 0;
-	/*
-	 * Decide on what work routines to call based on the inode size.
-	 */
+	rval = xfs_da_setup_name_and_hash(&args, name, namelen);
+	if (rval)
+		return rval;
+
 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 		rval = xfs_dir2_sf_removename(&args);
-	else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
-		return rval;
-	} else if (v)
+	else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
+		goto out;
+	else if (v)
 		rval = xfs_dir2_block_removename(&args);
-	else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
-		return rval;
-	} else if (v)
+	else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
+		goto out;
+	else if (v)
 		rval = xfs_dir2_leaf_removename(&args);
 	else
 		rval = xfs_dir2_node_removename(&args);
+out:
+	xfs_da_cleanup_name(&args, name);
 	return rval;
 }
 
 /*
  * Replace the inode number of a directory entry.
  */
-STATIC int				/* error */
+int
 xfs_dir2_replace(
-	xfs_trans_t	*tp,		/* transaction pointer */
-	xfs_inode_t	*dp,		/* incore directory inode */
+	xfs_trans_t	*tp,
+	xfs_inode_t	*dp,
 	uchar_t		*name,		/* name of entry to replace */
-	int		namelen,	/* name length of entry to replace */
+	int		namelen,
 	xfs_ino_t	inum,		/* new inode number */
 	xfs_fsblock_t	*first,		/* bmap's firstblock */
 	xfs_bmap_free_t	*flist,		/* bmap's freeblock list */
 	xfs_extlen_t	total)		/* bmap's total block count */
 {
-	xfs_da_args_t	args;		/* operation arguments */
-	int		rval;		/* return value */
+	xfs_da_args_t	args;
+	int		rval;
 	int		v;		/* type-checking value */
 
 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
-	if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
+	if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
 		return rval;
-	}
-	/*
-	 * Fill in the arg structure for this request.
-	 */
-	args.name = name;
-	args.namelen = namelen;
-	args.hashval = xfs_da_hashname(name, namelen);
+
 	args.inumber = inum;
 	args.dp = dp;
 	args.firstblock = first;
@@ -270,21 +313,24 @@
 	args.whichfork = XFS_DATA_FORK;
 	args.trans = tp;
 	args.justcheck = args.addname = args.oknoent = 0;
-	/*
-	 * Decide on what work routines to call based on the inode size.
-	 */
+	rval = xfs_da_setup_name_and_hash(&args, name, namelen);
+	if (rval)
+		return rval;
+
 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 		rval = xfs_dir2_sf_replace(&args);
-	else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
-		return rval;
-	} else if (v)
+	else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
+		goto out;
+	else if (v)
 		rval = xfs_dir2_block_replace(&args);
-	else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
-		return rval;
-	} else if (v)
+	else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
+		goto out;
+	else if (v)
 		rval = xfs_dir2_leaf_replace(&args);
 	else
 		rval = xfs_dir2_node_replace(&args);
+out:
+	xfs_da_cleanup_name(&args, name);
 	return rval;
 }
 
Index: ci/xfsprogs/libxfs/xfs_unicode.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ci/xfsprogs/libxfs/xfs_unicode.c	2008-01-18 15:00:09.176552528 +1100
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2007 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_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir2.h"
+#include "xfs_alloc.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_rtalloc.h"
+#include "xfs_bmap.h"
+#include "xfs_unicode.h"
+
+#define MAX_FOLD_CHARS	4
+
+static kmem_zone_t	*xfs_nls_uni_zone;
+
+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->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);
+}
+
+__uint32_t
+xfs_unicode_hash(
+	const xfs_cft_t	*cft,
+	const uchar_t	*name,
+	int		namelen)
+{
+	__uint32_t	hash = 0;
+	__uint16_t	fc[MAX_FOLD_CHARS];
+	int		nfc;
+	int		i;
+
+	while (namelen > 0) {
+		nfc = xfs_utf8_casefold(cft, &name, &namelen, fc);
+		for (i = 0; i < nfc; i++)
+			hash = fc[i] ^ rol32(hash, 7);
+	}
+	return hash;
+}
+
+int
+xfs_unicode_casecmp(
+	const 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 (*pfc1 < *pfc2) ? -1 : 1;
+		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 (nfc1 < nfc2) ? -1 : 1;
+	return 0;
+}
+
+
+char *
+xfs_alloc_unicode_nls_name(void)
+{
+	return kmem_zone_alloc(xfs_nls_uni_zone, KM_SLEEP);
+}
+
+
+void
+xfs_free_unicode_nls_name(
+	char		*name)
+{
+	kmem_zone_free(xfs_nls_uni_zone, name);
+}
+
+
+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)
+			return -EINVAL;
+		/* utf8_mbtowc must fail on overlong sequences too */
+		nlen = utf8_mbtowc(&uc, name + i, namelen - i);
+		if (nlen < 0)
+			return -EILSEQ;
+		/* check for invalid/surrogate/private unicode chars */
+		if (uc >= 0xfffe || (uc >= 0xd800 && uc <= 0xf8ff))
+			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->cft_num_tables != be32_to_cpu(dcft->cft_num_tables) ||
+				cft->cft_flags != be32_to_cpu(dcft->cft_flags))
+			continue;
+		found = 1;
+		for (j = 0; j < cft->cft_num_tables; j++) {
+			if (cft->cft_table_offset[j] !=
+					be32_to_cpu(dcft->cft_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->cft_magic = be32_to_cpu(dcft->cft_magic);
+	cft->cft_flags = be32_to_cpu(dcft->cft_flags);
+	cft->cft_num_tables = be32_to_cpu(dcft->cft_num_tables);
+	ASSERT(cft->cft_num_tables <= MAX_FOLD_CHARS);
+	for (i = 0; i < cft->cft_num_tables; i++)
+		cft->cft_table_offset[i] = be32_to_cpu(dcft->cft_table_offset[i]);
+	j = (size - cft->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);
+	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 (platform_uuid_compare(&dcft->cft_uuid, &mp->m_sb.sb_uuid) != 0) {
+		error = EINVAL;
+		goto out;
+	}
+
+	/* clear UUID for in-memory copy/compare */
+	memset(&dcft->cft_uuid, 0, sizeof(dcft->cft_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)
+{
+	remove_cft(cft);
+}
+
+void
+xfs_unicode_init(void)
+{
+	mutex_init(&cft_lock);
+	xfs_nls_uni_zone = kmem_zone_init(MAXNAMELEN, "xfs_nls_uni");
+}
+
+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);
+
+	kmem_zone_destroy(xfs_nls_uni_zone);
+}
Index: ci/xfsprogs/mdrestore/Makefile
===================================================================
--- ci.orig/xfsprogs/mdrestore/Makefile	2008-01-18 14:50:43.000000000 +1100
+++ ci/xfsprogs/mdrestore/Makefile	2008-01-18 15:00:09.272540212 +1100
@@ -8,7 +8,7 @@
 LTCOMMAND = xfs_mdrestore
 CFILES = xfs_mdrestore.c
 
-LLDLIBS = $(LIBXFS) $(LIBRT) $(LIBPTHREAD)
+LLDLIBS = $(LIBXFS) $(LIBUUID) $(LIBRT) $(LIBPTHREAD)
 LTDEPENDENCIES = $(LIBXFS)
 LLDFLAGS = -static
 
Index: ci/xfsprogs/db/cft.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ci/xfsprogs/db/cft.c	2008-01-18 15:00:09.336532002 +1100
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2000-2001,2005 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/libxfs.h>
+#include "command.h"
+#include "type.h"
+#include "faddr.h"
+#include "fprint.h"
+#include "field.h"
+#include "io.h"
+#include "bit.h"
+#include "output.h"
+#include "init.h"
+#include "inode.h"
+#include "bmap.h"
+
+static int	cft_f(int argc, char **argv);
+static void	cft_help(void);
+
+static int	cft_table_count(void *obj, int startoff);
+
+static const cmdinfo_t cft_cmd =
+	{ "cft", NULL, cft_f, 0, 0, 0, NULL,
+	  "set address to casefold table", cft_help };
+
+const field_t	cft_hfld[] = {
+	{ "", FLDT_CFT, OI(0), C1, 0, TYP_NONE },
+	{ NULL }
+};
+
+#define	OFF(f)	bitize(offsetof(xfs_cft_t, cft_ ## f))
+#define	SZ(f)	bitszof(xfs_cft_t, cft_ ## f)
+const field_t	cft_flds[] = {
+	{ "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE },
+	{ "flags", FLDT_UINT32X, OI(OFF(flags)), C1, 0, TYP_NONE },
+	{ "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE },
+	{ "crc", FLDT_UINT32X, OI(OFF(crc)), C1, 0, TYP_NONE },
+	{ "num_tables", FLDT_UINT32D, OI(OFF(num_tables)), C1, 0, TYP_NONE },
+	{ "table_offset", FLDT_UINT32D, OI(OFF(table_offset)), cft_table_count,
+			FLD_ARRAY | FLD_COUNT, TYP_NONE },
+	{ NULL }
+};
+
+static void
+cft_help(void)
+{
+	dbprintf(
+"\n"
+" set address to casefold table\n"
+"\n"
+" Example:\n"
+"\n"
+" cft - move location to filesystem casefold table\n"
+"\n"
+" The casefold table is stored in a file for Unicode aware filesystems.\n"
+" All directory and attribute names are hashed using the casefold table.\n"
+);
+}
+
+static int
+cft_f(
+	int		argc,
+	char		**argv)
+{
+	bmap_ext_t	bmp;
+	xfs_dfiloff_t	bno;
+	int		nex;
+	typnm_t		type;
+
+	if (!xfs_sb_version_hasunicode(&mp->m_sb)) {
+		dbprintf("filesystem does not have a casefold table\n");
+		return 0;
+	}
+
+	set_cur_inode(mp->m_sb.sb_cftino);
+	type = inode_next_type();
+	if (!type != TYP_CFT) {
+		dbprintf("cannot read casefold table\n");
+		return 0;
+	}
+
+	nex = 1;
+	bmap(bno, 1, XFS_DATA_FORK, &nex, &bmp);
+	if (nex == 0) {
+		dbprintf("casefold table block is unmapped\n");
+		return 0;
+	}
+	ASSERT(typtab[type].typnm == type);
+	ASSERT(nex == 1);
+	set_cur(&typtab[type], (__int64_t)XFS_FSB_TO_DADDR(mp, bmp.startblock),
+		blkbb, DB_RING_ADD, NULL);
+	return 0;
+}
+
+void
+cft_init(void)
+{
+	add_command(&cft_cmd);
+}
+
+int
+cft_size(
+	void	*obj,
+	int	startoff,
+	int	idx)
+{
+	return bitize(mp->m_sb.sb_blocksize);
+}
+
+static int
+cft_table_count(
+	void		*obj,
+	int		startoff)
+{
+	xfs_dcft_t	*cft;
+
+	ASSERT(startoff == 0);
+	cft = obj;
+	return be32_to_cpu(cft->cft_num_tables);
+}
Index: ci/xfsprogs/db/cft.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ci/xfsprogs/db/cft.h	2008-01-18 15:00:09.348530462 +1100
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 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
+ */
+
+extern const struct field	cft_flds[];
+extern const struct field	cft_hfld[];
+
+extern void	cft_init(void);
+extern int	cft_size(void *obj, int startoff, int idx);
Index: ci/xfsprogs/libxfs/utf8.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ci/xfsprogs/libxfs/utf8.c	2008-01-18 15:00:09.348530462 +1100
@@ -0,0 +1,85 @@
+/*
+ * The following was provided by Ken Thompson of AT&T Bell Laboratories,
+ * <ken@research.att.com>, on Tue, 8 Sep 92 03:22:07 EDT, to the X/Open
+ * Joint Internationalization Group.
+ */
+
+#include <stdlib.h>
+
+struct utf8_table {
+	int     cmask;
+	int     cval;
+	int     shift;
+	long    lmask;
+	long    lval;
+};
+
+static const struct utf8_table utf8_table[] =
+{
+    {0x80,  0x00,   0*6,    0x7F,           0,         /* 1 byte sequence */},
+    {0xE0,  0xC0,   1*6,    0x7FF,          0x80,      /* 2 byte sequence */},
+    {0xF0,  0xE0,   2*6,    0xFFFF,         0x800,     /* 3 byte sequence */},
+    {0xF8,  0xF0,   3*6,    0x1FFFFF,       0x10000,   /* 4 byte sequence */},
+    {0xFC,  0xF8,   4*6,    0x3FFFFFF,      0x200000,  /* 5 byte sequence */},
+    {0xFE,  0xFC,   5*6,    0x7FFFFFFF,     0x4000000, /* 6 byte sequence */},
+    {0,						       /* end of table    */}
+};
+
+int
+utf8_mbtowc(wchar_t *p, const unsigned char *s, int n)
+{
+	long l;
+	int c0, c, nc;
+	const struct utf8_table *t;
+
+	nc = 0;
+	c0 = *s;
+	l = c0;
+	for (t = utf8_table; t->cmask; t++) {
+		nc++;
+		if ((c0 & t->cmask) == t->cval) {
+			l &= t->lmask;
+			if (l < t->lval)
+				return -1;
+			*p = l;
+			return nc;
+		}
+		if (n <= nc)
+			return -1;
+		s++;
+		c = (*s ^ 0x80) & 0xFF;
+		if (c & 0xC0)
+			return -1;
+		l = (l << 6) | c;
+	}
+	return -1;
+}
+
+int
+utf8_wctomb(unsigned char *s, wchar_t wc, int maxlen)
+{
+	long l;
+	int c, nc;
+	const struct utf8_table *t;
+
+	if (!s)
+		return 0;
+
+	l = wc;
+	nc = 0;
+	for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) {
+		nc++;
+		if (l <= t->lmask) {
+			c = t->shift;
+			*s = t->cval | (l >> c);
+			while (c > 0) {
+				c -= 6;
+				s++;
+				*s = 0x80 | ((l >> c) & 0x3F);
+			}
+			return nc;
+		}
+	}
+	return -1;
+}
+
Index: ci/xfsprogs/libxfs/xfs_dir2_block.c
===================================================================
--- ci.orig/xfsprogs/libxfs/xfs_dir2_block.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/libxfs/xfs_dir2_block.c	2008-01-18 15:00:09.352529949 +1100
@@ -1046,8 +1046,9 @@
 		tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
 		INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
 		xfs_dir2_data_log_entry(tp, bp, dep);
-		INT_SET(blp[2 + i].hashval, ARCH_CONVERT, xfs_da_hashname((const uchar_t *)sfep->name, sfep->namelen));
-		INT_SET(blp[2 + i].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp,
+		blp[2 + i].hashval = cpu_to_be32(xfs_dir_hashname(dp,
+						sfep->name, sfep->namelen));
+		blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
 						 (char *)dep - (char *)block));
 		offset = (int)((char *)(tagp + 1) - (char *)block);
 		if (++i == INT_GET(sfp->hdr.count, ARCH_CONVERT))
Index: ci/xfsprogs/libxfs/xfs_dir2_data.c
===================================================================
--- ci.orig/xfsprogs/libxfs/xfs_dir2_data.c	2008-01-18 14:50:42.000000000 +1100
+++ ci/xfsprogs/libxfs/xfs_dir2_data.c	2008-01-18 15:00:09.352529949 +1100
@@ -126,7 +126,8 @@
 			addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
 				(xfs_dir2_data_aoff_t)
 				((char *)dep - (char *)d));
-			hash = xfs_da_hashname((char *)dep->name, dep->namelen);
+			hash = xfs_dir_hashname(dp, (char *)dep->name,
+					dep->namelen);
 			for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) {
 				if (INT_GET(lep[i].address, ARCH_CONVERT) == addr &&
 				    INT_GET(lep[i].hashval, ARCH_CONVERT) == hash)

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2008-01-21  2:31 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-18  4:43 [REVIEW 2/2] Case insensitive support for XFS - user-space Barry Naujok
2008-01-18 21:23 ` Eric Sandeen
2008-01-19  6:00   ` Eric Sandeen
2008-01-21  2:07     ` Barry Naujok
2008-01-21  2:16       ` Barry Naujok
2008-01-21  2:31         ` Eric Sandeen
2008-01-21  0:54   ` Barry Naujok

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox