1 diff -urp linux-stage.orig/fs/ext4/dir.c linux-stage/fs/ext4/dir.c
2 --- linux-stage.orig/fs/ext4/dir.c 2012-06-21 10:26:23.000000000 -0400
3 +++ linux-stage/fs/ext4/dir.c 2012-06-21 10:37:39.000000000 -0400
4 @@ -247,22 +247,63 @@ out:
8 +static inline int is_32bit_api(void)
10 +#ifdef HAVE_IS_COMPAT_TASK
11 + return is_compat_task();
13 + return (BITS_PER_LONG == 32);
18 * These functions convert from the major/minor hash to an f_pos
20 + * value for dx directories.
22 - * Currently we only use major hash numer. This is unfortunate, but
23 - * on 32-bit machines, the same VFS interface is used for lseek and
24 - * llseek, so if we use the 64 bit offset, then the 32-bit versions of
25 - * lseek/telldir/seekdir will blow out spectacularly, and from within
26 - * the ext2 low-level routine, we don't know if we're being called by
27 - * a 64-bit version of the system call or the 32-bit version of the
28 - * system call. Worse yet, NFSv2 only allows for a 32-bit readdir
30 + * Upper layer (for example NFS) should specify FMODE_32BITHASH or
31 + * FMODE_64BITHASH explicitly. On the other hand, we allow ext4 to be mounted
32 + * directly on both 32-bit and 64-bit nodes, under such case, neither
33 + * FMODE_32BITHASH nor FMODE_64BITHASH is specified.
35 +static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor)
37 + if ((filp->f_mode & FMODE_32BITHASH) ||
38 + (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
41 + return ((__u64)(major >> 1) << 32) | (__u64)minor;
44 +static inline __u32 pos2maj_hash(struct file *filp, loff_t pos)
46 + if ((filp->f_mode & FMODE_32BITHASH) ||
47 + (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
48 + return (pos << 1) & 0xffffffff;
50 + return ((pos >> 32) << 1) & 0xffffffff;
53 +static inline __u32 pos2min_hash(struct file *filp, loff_t pos)
55 + if ((filp->f_mode & FMODE_32BITHASH) ||
56 + (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
59 + return pos & 0xffffffff;
63 + * Return 32- or 64-bit end-of-file for dx directories
65 -#define hash2pos(major, minor) (major >> 1)
66 -#define pos2maj_hash(pos) ((pos << 1) & 0xffffffff)
67 -#define pos2min_hash(pos) (0)
68 +static inline loff_t ext4_get_htree_eof(struct file *filp)
70 + if ((filp->f_mode & FMODE_32BITHASH) ||
71 + (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
72 + return EXT4_HTREE_EOF_32BIT;
74 + return EXT4_HTREE_EOF_64BIT;
79 * This structure holds the nodes of the red-black tree used to store
80 @@ -323,15 +364,16 @@ static void free_rb_tree_fname(struct rb
84 -static struct dir_private_info *ext4_htree_create_dir_info(loff_t pos)
85 +static struct dir_private_info *
86 +ext4_htree_create_dir_info(struct file *filp, loff_t pos)
88 struct dir_private_info *p;
90 p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL);
93 - p->curr_hash = pos2maj_hash(pos);
94 - p->curr_minor_hash = pos2min_hash(pos);
95 + p->curr_hash = pos2maj_hash(filp, pos);
96 + p->curr_minor_hash = pos2min_hash(filp, pos);
100 @@ -427,7 +469,7 @@ static int call_filldir(struct file *fil
104 - curr_pos = hash2pos(fname->hash, fname->minor_hash);
105 + curr_pos = hash2pos(filp, fname->hash, fname->minor_hash);
107 error = filldir(dirent, fname->name,
108 fname->name_len, curr_pos,
109 @@ -452,13 +494,13 @@ static int ext4_dx_readdir(struct file *
113 - info = ext4_htree_create_dir_info(filp->f_pos);
114 + info = ext4_htree_create_dir_info(filp, filp->f_pos);
117 filp->private_data = info;
120 - if (filp->f_pos == EXT4_HTREE_EOF)
121 + if (filp->f_pos == ext4_get_htree_eof(filp))
124 /* Some one has messed with f_pos; reset the world */
125 @@ -466,8 +508,8 @@ static int ext4_dx_readdir(struct file *
126 free_rb_tree_fname(&info->root);
127 info->curr_node = NULL;
128 info->extra_fname = NULL;
129 - info->curr_hash = pos2maj_hash(filp->f_pos);
130 - info->curr_minor_hash = pos2min_hash(filp->f_pos);
131 + info->curr_hash = pos2maj_hash(filp, filp->f_pos);
132 + info->curr_minor_hash = pos2min_hash(filp, filp->f_pos);
136 @@ -499,7 +541,7 @@ static int ext4_dx_readdir(struct file *
140 - filp->f_pos = EXT4_HTREE_EOF;
141 + filp->f_pos = ext4_get_htree_eof(filp);
144 info->curr_node = rb_first(&info->root);
145 @@ -519,7 +561,7 @@ static int ext4_dx_readdir(struct file *
146 info->curr_minor_hash = fname->minor_hash;
148 if (info->next_hash == ~0) {
149 - filp->f_pos = EXT4_HTREE_EOF;
150 + filp->f_pos = ext4_get_htree_eof(filp);
153 info->curr_hash = info->next_hash;
154 diff -urp linux-stage.orig/fs/ext4/ext4.h linux-stage/fs/ext4/ext4.h
155 --- linux-stage.orig/fs/ext4/ext4.h 2012-06-21 10:26:23.000000000 -0400
156 +++ linux-stage/fs/ext4/ext4.h 2012-06-21 10:39:43.000000000 -0400
157 @@ -816,6 +816,16 @@ struct ext4_inode_info {
161 +#ifndef FMODE_32BITHASH
162 +/* 32bit hashes as llseek() offset (for directories) */
163 +#define FMODE_32BITHASH ((__force fmode_t)0x200)
166 +#ifndef FMODE_64BITHASH
167 +/* 64bit hashes as llseek() offset (for directories) */
168 +#define FMODE_64BITHASH ((__force fmode_t)0x400)
171 #define HAVE_DISK_INODE_VERSION
174 @@ -1450,7 +1460,11 @@ struct dx_hash_info
178 -#define EXT4_HTREE_EOF 0x7fffffff
180 +/* 32 and 64 bit signed EOF for dx directories */
181 +#define EXT4_HTREE_EOF_32BIT ((1UL << (32 - 1)) - 1)
182 +#define EXT4_HTREE_EOF_64BIT ((1ULL << (64 - 1)) - 1)
186 * Control parameters used by ext4_htree_next_block
187 diff -urp linux-stage.orig/fs/ext4/hash.c linux-stage/fs/ext4/hash.c
188 --- linux-stage.orig/fs/ext4/hash.c 2012-06-21 10:26:23.000000000 -0400
189 +++ linux-stage/fs/ext4/hash.c 2012-06-21 10:29:02.000000000 -0400
190 @@ -201,8 +201,8 @@ int ext4fs_dirhash(const char *name, int
194 - if (hash == (EXT4_HTREE_EOF << 1))
195 - hash = (EXT4_HTREE_EOF-1) << 1;
196 + if (hash == (EXT4_HTREE_EOF_32BIT << 1))
197 + hash = (EXT4_HTREE_EOF_32BIT - 1) << 1;
199 hinfo->minor_hash = minor_hash;