Whamcloud - gitweb
LU-8364 ldiskfs: fixes for failover mode
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / rhel6.3 / ext4-export-64bit-name-hash.patch
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,20 +247,52 @@ out:
5
6  /*
7   * These functions convert from the major/minor hash to an f_pos
8 - * value.
9 + * value for dx directories.
10   *
11 - * Currently we only use major hash numer.  This is unfortunate, but
12 - * on 32-bit machines, the same VFS interface is used for lseek and
13 - * llseek, so if we use the 64 bit offset, then the 32-bit versions of
14 - * lseek/telldir/seekdir will blow out spectacularly, and from within
15 - * the ext2 low-level routine, we don't know if we're being called by
16 - * a 64-bit version of the system call or the 32-bit version of the
17 - * system call.  Worse yet, NFSv2 only allows for a 32-bit readdir
18 - * cookie.  Sigh.
19 + * Upper layer (for example NFS) should specify FMODE_32BITHASH or
20 + * FMODE_64BITHASH explicitly. On the other hand, we allow ext4 to be mounted
21 + * directly on both 32-bit and 64-bit nodes, under such case, neither
22 + * FMODE_32BITHASH nor FMODE_64BITHASH is specified.
23 + */
24 +static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor)
25 +{
26 +       if ((filp->f_mode & FMODE_32BITHASH) ||
27 +           (!(filp->f_mode & FMODE_64BITHASH) && is_compat_task()))
28 +               return major >> 1;
29 +       else
30 +               return ((__u64)(major >> 1) << 32) | (__u64)minor;
31 +}
32 +
33 +static inline __u32 pos2maj_hash(struct file *filp, loff_t pos)
34 +{
35 +       if ((filp->f_mode & FMODE_32BITHASH) ||
36 +           (!(filp->f_mode & FMODE_64BITHASH) && is_compat_task()))
37 +               return (pos << 1) & 0xffffffff;
38 +       else
39 +               return ((pos >> 32) << 1) & 0xffffffff;
40 +}
41 +
42 +static inline __u32 pos2min_hash(struct file *filp, loff_t pos)
43 +{
44 +       if ((filp->f_mode & FMODE_32BITHASH) ||
45 +           (!(filp->f_mode & FMODE_64BITHASH) && is_compat_task()))
46 +               return 0;
47 +       else
48 +               return pos & 0xffffffff;
49 +}
50 +
51 +/*
52 + * Return 32- or 64-bit end-of-file for dx directories
53   */
54 -#define hash2pos(major, minor) (major >> 1)
55 -#define pos2maj_hash(pos)      ((pos << 1) & 0xffffffff)
56 -#define pos2min_hash(pos)      (0)
57 +static inline loff_t ext4_get_htree_eof(struct file *filp)
58 +{
59 +       if ((filp->f_mode & FMODE_32BITHASH) ||
60 +           (!(filp->f_mode & FMODE_64BITHASH) && is_compat_task()))
61 +               return EXT4_HTREE_EOF_32BIT;
62 +       else
63 +               return EXT4_HTREE_EOF_64BIT;
64 +}
65 +
66  
67  /*
68   * This structure holds the nodes of the red-black tree used to store
69 @@ -323,15 +364,16 @@ static void free_rb_tree_fname(struct rb
70  }
71  
72  
73 -static struct dir_private_info *ext4_htree_create_dir_info(loff_t pos)
74 +static struct dir_private_info *
75 +ext4_htree_create_dir_info(struct file *filp, loff_t pos)
76  {
77         struct dir_private_info *p;
78  
79         p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL);
80         if (!p)
81                 return NULL;
82 -       p->curr_hash = pos2maj_hash(pos);
83 -       p->curr_minor_hash = pos2min_hash(pos);
84 +       p->curr_hash = pos2maj_hash(filp, pos);
85 +       p->curr_minor_hash = pos2min_hash(filp, pos);
86         return p;
87  }
88  
89 @@ -427,7 +469,7 @@ static int call_filldir(struct file *fil
90                        "null fname?!?\n");
91                 return 0;
92         }
93 -       curr_pos = hash2pos(fname->hash, fname->minor_hash);
94 +       curr_pos = hash2pos(filp, fname->hash, fname->minor_hash);
95         while (fname) {
96                 error = filldir(dirent, fname->name,
97                                 fname->name_len, curr_pos,
98 @@ -452,13 +494,13 @@ static int ext4_dx_readdir(struct file *
99         int     ret;
100  
101         if (!info) {
102 -               info = ext4_htree_create_dir_info(filp->f_pos);
103 +               info = ext4_htree_create_dir_info(filp, filp->f_pos);
104                 if (!info)
105                         return -ENOMEM;
106                 filp->private_data = info;
107         }
108
109 -       if (filp->f_pos == EXT4_HTREE_EOF)
110 +       if (filp->f_pos == ext4_get_htree_eof(filp))
111                 return 0;       /* EOF */
112
113         /* Some one has messed with f_pos; reset the world */
114 @@ -466,8 +508,8 @@ static int ext4_dx_readdir(struct file *
115                 free_rb_tree_fname(&info->root);
116                 info->curr_node = NULL;
117                 info->extra_fname = NULL;
118 -               info->curr_hash = pos2maj_hash(filp->f_pos);
119 -               info->curr_minor_hash = pos2min_hash(filp->f_pos);
120 +               info->curr_hash = pos2maj_hash(filp, filp->f_pos);
121 +               info->curr_minor_hash = pos2min_hash(filp, filp->f_pos);
122         }
123  
124         /*
125 @@ -499,7 +541,7 @@ static int ext4_dx_readdir(struct file *
126                         if (ret < 0)
127                                 return ret;
128                         if (ret == 0) {
129 -                               filp->f_pos = EXT4_HTREE_EOF;
130 +                               filp->f_pos = ext4_get_htree_eof(filp);
131                                 break;
132                         }
133                         info->curr_node = rb_first(&info->root);
134 @@ -519,7 +561,7 @@ static int ext4_dx_readdir(struct file *
135                         info->curr_minor_hash = fname->minor_hash;
136                 } else {
137                         if (info->next_hash == ~0) {
138 -                               filp->f_pos = EXT4_HTREE_EOF;
139 +                               filp->f_pos = ext4_get_htree_eof(filp);
140                                 break;
141                         }
142                         info->curr_hash = info->next_hash;
143 diff -urp linux-stage.orig/fs/ext4/ext4.h linux-stage/fs/ext4/ext4.h
144 --- linux-stage.orig/fs/ext4/ext4.h     2012-06-21 10:26:23.000000000 -0400
145 +++ linux-stage/fs/ext4/ext4.h  2012-06-21 10:39:43.000000000 -0400
146 @@ -816,6 +816,16 @@ struct ext4_inode_info {
147         __u64 i_fs_version;
148  };
149  
150 +#ifndef FMODE_32BITHASH
151 +/* 32bit hashes as llseek() offset (for directories) */
152 +#define FMODE_32BITHASH         ((__force fmode_t)0x200)
153 +#endif
154 +
155 +#ifndef FMODE_64BITHASH
156 +/* 64bit hashes as llseek() offset (for directories) */
157 +#define FMODE_64BITHASH         ((__force fmode_t)0x400)
158 +#endif
159 +
160  #define HAVE_DISK_INODE_VERSION
161  
162  /*
163 @@ -1450,7 +1460,11 @@ struct dx_hash_info
164         u32             *seed;
165  };
166
167 -#define EXT4_HTREE_EOF 0x7fffffff
168 +
169 +/* 32 and 64 bit signed EOF for dx directories */
170 +#define EXT4_HTREE_EOF_32BIT   ((1UL  << (32 - 1)) - 1)
171 +#define EXT4_HTREE_EOF_64BIT   ((1ULL << (64 - 1)) - 1)
172 +
173
174  /*
175   * Control parameters used by ext4_htree_next_block
176 diff -urp linux-stage.orig/fs/ext4/hash.c linux-stage/fs/ext4/hash.c
177 --- linux-stage.orig/fs/ext4/hash.c     2012-06-21 10:26:23.000000000 -0400
178 +++ linux-stage/fs/ext4/hash.c  2012-06-21 10:29:02.000000000 -0400
179 @@ -201,8 +201,8 @@ int ext4fs_dirhash(const char *name, int
180                 return -1;
181         }
182         hash = hash & ~1;
183 -       if (hash == (EXT4_HTREE_EOF << 1))
184 -               hash = (EXT4_HTREE_EOF-1) << 1;
185 +       if (hash == (EXT4_HTREE_EOF_32BIT << 1))
186 +               hash = (EXT4_HTREE_EOF_32BIT - 1) << 1;
187         hinfo->hash = hash;
188         hinfo->minor_hash = minor_hash;
189         return 0;