-Index: linux-2.6.18-194.17.1-ext4/fs/ext4/dir.c
+Index: linux-stage/fs/ext4/dir.c
===================================================================
---- linux-2.6.18-194.17.1-ext4.orig/fs/ext4/dir.c 2010-12-02 16:37:05.000000000 +0300
-+++ linux-2.6.18-194.17.1-ext4/fs/ext4/dir.c 2010-12-16 00:06:49.000000000 +0300
-@@ -245,19 +245,32 @@ out:
+--- linux-stage.orig/fs/ext4/dir.c 2011-04-19 01:02:34.000000000 +0800
++++ linux-stage/fs/ext4/dir.c 2011-04-19 01:24:36.000000000 +0800
+@@ -242,22 +242,50 @@
+ return ret;
+ }
+
++static inline int is_32bit_api(void)
++{
++#ifdef HAVE_IS_COMPAT_TASK
++ return is_compat_task();
++#else
++ return (BITS_PER_LONG == 32);
++#endif
++}
++
/*
* These functions convert from the major/minor hash to an f_pos
* value.
-- *
+ *
- * Currently we only use major hash numer. This is unfortunate, but
- * on 32-bit machines, the same VFS interface is used for lseek and
- * llseek, so if we use the 64 bit offset, then the 32-bit versions of
- * a 64-bit version of the system call or the 32-bit version of the
- * system call. Worse yet, NFSv2 only allows for a 32-bit readdir
- * cookie. Sigh.
-+ * Whether 64-bit or 32-bit hash value is exported as file pos is
-+ * controlled by "64bithash" mount option.
++ * Up layer (OSD) should specify O_32BITHASH or O_64BITHASH explicitly.
++ * On the other hand, we allow ldiskfs to be mounted directly on both 32-bit
++ * and 64-bit nodes, under such case, neither O_32BITHASH nor O_64BITHASH is
++ * specified.
*/
-#define hash2pos(major, minor) (major >> 1)
-#define pos2maj_hash(pos) ((pos << 1) & 0xffffffff)
-#define pos2min_hash(pos) (0)
-+static inline loff_t hash2pos(struct super_block *sb, __u32 major, __u32 minor)
++static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor)
+{
-+ if (test_opt(sb, 64BITHASH))
-+ return (((__u64)(major >> 1) << 32) | (__u64)minor);
-+ else
++ if ((filp->f_flags & O_32BITHASH) ||
++ (!(filp->f_flags & O_64BITHASH) && is_32bit_api()))
+ return (major >> 1);
++ else
++ return (((__u64)(major >> 1) << 32) | (__u64)minor);
+}
+
-+static inline __u32 pos2maj_hash(struct super_block *sb, loff_t pos)
++static inline __u32 pos2maj_hash(struct file *filp, loff_t pos)
+{
-+ if (test_opt(sb, 64BITHASH))
-+ return (((pos >> 32) << 1) & 0xffffffff);
-+ else
++ if ((filp->f_flags & O_32BITHASH) ||
++ (!(filp->f_flags & O_64BITHASH) && is_32bit_api()))
+ return ((pos << 1) & 0xffffffff);
++ else
++ return (((pos >> 32) << 1) & 0xffffffff);
+}
+
-+static inline __u32 pos2min_hash(struct super_block *sb, loff_t pos)
++static inline __u32 pos2min_hash(struct file *filp, loff_t pos)
+{
-+ if (test_opt(sb, 64BITHASH))
-+ return (pos & 0xffffffff);
-+ else
++ if ((filp->f_flags & O_32BITHASH) ||
++ (!(filp->f_flags & O_64BITHASH) && is_32bit_api()))
+ return (0);
++ else
++ return (pos & 0xffffffff);
+}
/*
* This structure holds the nodes of the red-black tree used to store
-@@ -318,15 +331,16 @@ static void free_rb_tree_fname(struct rb
+@@ -318,15 +346,16 @@
}
-static struct dir_private_info *ext4_htree_create_dir_info(loff_t pos)
-+static struct dir_private_info *ext4_htree_create_dir_info(
-+ struct super_block *sb, loff_t pos)
++static struct dir_private_info *
++ext4_htree_create_dir_info(struct file *filp, loff_t pos)
{
struct dir_private_info *p;
return NULL;
- p->curr_hash = pos2maj_hash(pos);
- p->curr_minor_hash = pos2min_hash(pos);
-+ p->curr_hash = pos2maj_hash(sb, pos);
-+ p->curr_minor_hash = pos2min_hash(sb, pos);
++ p->curr_hash = pos2maj_hash(filp, pos);
++ p->curr_minor_hash = pos2min_hash(filp, pos);
return p;
}
-@@ -422,7 +436,7 @@ static int call_filldir(struct file *fil
+@@ -422,7 +451,7 @@
"null fname?!?\n");
return 0;
}
- curr_pos = hash2pos(fname->hash, fname->minor_hash);
-+ curr_pos = hash2pos(sb, fname->hash, fname->minor_hash);
++ curr_pos = hash2pos(filp, fname->hash, fname->minor_hash);
while (fname) {
error = filldir(dirent, fname->name,
fname->name_len, curr_pos,
-@@ -447,7 +461,7 @@ static int ext4_dx_readdir(struct file *
+@@ -447,7 +476,7 @@
int ret;
if (!info) {
- info = ext4_htree_create_dir_info(filp->f_pos);
-+ info = ext4_htree_create_dir_info(inode->i_sb, filp->f_pos);
++ info = ext4_htree_create_dir_info(filp, filp->f_pos);
if (!info)
return -ENOMEM;
filp->private_data = info;
-@@ -461,8 +475,8 @@ static int ext4_dx_readdir(struct file *
+@@ -461,8 +490,8 @@
free_rb_tree_fname(&info->root);
info->curr_node = NULL;
info->extra_fname = NULL;
- info->curr_hash = pos2maj_hash(filp->f_pos);
- info->curr_minor_hash = pos2min_hash(filp->f_pos);
-+ info->curr_hash = pos2maj_hash(inode->i_sb, filp->f_pos);
-+ info->curr_minor_hash = pos2min_hash(inode->i_sb, filp->f_pos);
++ info->curr_hash = pos2maj_hash(filp, filp->f_pos);
++ info->curr_minor_hash = pos2min_hash(filp, filp->f_pos);
}
/*
-Index: linux-2.6.18-194.17.1-ext4/fs/ext4/ext4.h
-===================================================================
---- linux-2.6.18-194.17.1-ext4.orig/fs/ext4/ext4.h 2010-12-03 11:05:04.000000000 +0300
-+++ linux-2.6.18-194.17.1-ext4/fs/ext4/ext4.h 2010-12-16 00:13:32.000000000 +0300
-@@ -741,6 +741,7 @@ struct ext4_inode_info {
- #define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */
- #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */
- #define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */
-+#define EXT4_MOUNT_64BITHASH 0x4000000 /* export 64-bit name hash */
- #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */
- #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
- #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */
-Index: linux-2.6.18-194.17.1-ext4/fs/ext4/super.c
+Index: linux-stage/fs/ext4/ext4.h
===================================================================
---- linux-2.6.18-194.17.1-ext4.orig/fs/ext4/super.c 2010-12-02 21:10:39.000000000 +0300
-+++ linux-2.6.18-194.17.1-ext4/fs/ext4/super.c 2010-12-15 23:57:43.000000000 +0300
-@@ -1479,6 +1479,7 @@ enum {
- Opt_iopen, Opt_noiopen, Opt_iopen_nopriv, Opt_bigendian_extents,
- Opt_force_over_16tb,
- Opt_no_mbcache,
-+ Opt_64bithash,
- };
+--- linux-stage.orig/fs/ext4/ext4.h 2011-04-19 01:02:34.000000000 +0800
++++ linux-stage/fs/ext4/ext4.h 2011-04-19 01:02:34.000000000 +0800
+@@ -55,6 +55,14 @@
+ #define ext4_debug(f, a...) do {} while (0)
+ #endif
- static match_table_t tokens = {
-@@ -1552,6 +1553,7 @@ static match_table_t tokens = {
- {Opt_bigendian_extents, "bigendian_extents"},
- {Opt_force_over_16tb, "force_over_16tb"},
- {Opt_no_mbcache, "no_mbcache"},
-+ {Opt_64bithash, "64bithash"},
- {Opt_err, NULL},
- };
++#ifndef O_32BITHASH
++# define O_32BITHASH 0x10000000
++#endif
++
++#ifndef O_64BITHASH
++# define O_64BITHASH 0x20000000
++#endif
++
+ #define HAVE_DISK_INODE_VERSION
-@@ -2004,6 +2006,9 @@ set_qf_format:
- case Opt_no_mbcache:
- set_opt(sbi->s_mount_opt, NO_MBCACHE);
- break;
-+ case Opt_64bithash:
-+ set_opt(sbi->s_mount_opt, 64BITHASH);
-+ break;
- default:
- ext4_msg(sb, KERN_ERR,
- "Unrecognized mount option \"%s\" "
+ /* data type for block offset of block group */