Whamcloud - gitweb
LU-2658 llite: too many arguments in generic_file_llseek_size
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / 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,22 +247,63 @@ out:
5         return ret;
6  }
7
8 +static inline int is_32bit_api(void)
9 +{
10 +#ifdef HAVE_IS_COMPAT_TASK
11 +        return is_compat_task();
12 +#else
13 +        return (BITS_PER_LONG == 32);
14 +#endif
15 +}
16 +
17  /*
18   * These functions convert from the major/minor hash to an f_pos
19 - * value.
20 + * value for dx directories.
21   *
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
29 - * cookie.  Sigh.
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.
34 + */
35 +static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor)
36 +{
37 +       if ((filp->f_mode & FMODE_32BITHASH) ||
38 +           (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
39 +               return major >> 1;
40 +       else
41 +               return ((__u64)(major >> 1) << 32) | (__u64)minor;
42 +}
43 +
44 +static inline __u32 pos2maj_hash(struct file *filp, loff_t pos)
45 +{
46 +       if ((filp->f_mode & FMODE_32BITHASH) ||
47 +           (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
48 +               return (pos << 1) & 0xffffffff;
49 +       else
50 +               return ((pos >> 32) << 1) & 0xffffffff;
51 +}
52 +
53 +static inline __u32 pos2min_hash(struct file *filp, loff_t pos)
54 +{
55 +       if ((filp->f_mode & FMODE_32BITHASH) ||
56 +           (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
57 +               return 0;
58 +       else
59 +               return pos & 0xffffffff;
60 +}
61 +
62 +/*
63 + * Return 32- or 64-bit end-of-file for dx directories
64   */
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)
69 +{
70 +       if ((filp->f_mode & FMODE_32BITHASH) ||
71 +           (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
72 +               return EXT4_HTREE_EOF_32BIT;
73 +       else
74 +               return EXT4_HTREE_EOF_64BIT;
75 +}
76 +
77  
78  /*
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
81  }
82  
83  
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)
87  {
88         struct dir_private_info *p;
89  
90         p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL);
91         if (!p)
92                 return NULL;
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);
97         return p;
98  }
99  
100 @@ -427,7 +469,7 @@ static int call_filldir(struct file *fil
101                        "null fname?!?\n");
102                 return 0;
103         }
104 -       curr_pos = hash2pos(fname->hash, fname->minor_hash);
105 +       curr_pos = hash2pos(filp, fname->hash, fname->minor_hash);
106         while (fname) {
107                 error = filldir(dirent, fname->name,
108                                 fname->name_len, curr_pos,
109 @@ -452,13 +494,13 @@ static int ext4_dx_readdir(struct file *
110         int     ret;
111  
112         if (!info) {
113 -               info = ext4_htree_create_dir_info(filp->f_pos);
114 +               info = ext4_htree_create_dir_info(filp, filp->f_pos);
115                 if (!info)
116                         return -ENOMEM;
117                 filp->private_data = info;
118         }
119
120 -       if (filp->f_pos == EXT4_HTREE_EOF)
121 +       if (filp->f_pos == ext4_get_htree_eof(filp))
122                 return 0;       /* EOF */
123
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);
133         }
134  
135         /*
136 @@ -499,7 +541,7 @@ static int ext4_dx_readdir(struct file *
137                         if (ret < 0)
138                                 return ret;
139                         if (ret == 0) {
140 -                               filp->f_pos = EXT4_HTREE_EOF;
141 +                               filp->f_pos = ext4_get_htree_eof(filp);
142                                 break;
143                         }
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;
147                 } else {
148                         if (info->next_hash == ~0) {
149 -                               filp->f_pos = EXT4_HTREE_EOF;
150 +                               filp->f_pos = ext4_get_htree_eof(filp);
151                                 break;
152                         }
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 {
158         __u64 i_fs_version;
159  };
160  
161 +#ifndef FMODE_32BITHASH
162 +/* 32bit hashes as llseek() offset (for directories) */
163 +#define FMODE_32BITHASH         ((__force fmode_t)0x200)
164 +#endif
165 +
166 +#ifndef FMODE_64BITHASH
167 +/* 64bit hashes as llseek() offset (for directories) */
168 +#define FMODE_64BITHASH         ((__force fmode_t)0x400)
169 +#endif
170 +
171  #define HAVE_DISK_INODE_VERSION
172  
173  /*
174 @@ -1450,7 +1460,11 @@ struct dx_hash_info
175         u32             *seed;
176  };
177
178 -#define EXT4_HTREE_EOF 0x7fffffff
179 +
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)
183 +
184
185  /*
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
191                 return -1;
192         }
193         hash = hash & ~1;
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;
198         hinfo->hash = hash;
199         hinfo->minor_hash = minor_hash;
200         return 0;