Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / quota-large-limits-rhel5.patch
1 Index: linux-2.6.18-128.1.6/fs/dquot.c
2 ===================================================================
3 --- linux-2.6.18-128.1.6.orig/fs/dquot.c        2009-04-14 21:04:50.000000000 -0600
4 +++ linux-2.6.18-128.1.6/fs/dquot.c     2009-06-02 23:26:36.000000000 -0600
5 @@ -1592,10 +1592,19 @@
6  }
7  
8  /* Generic routine for setting common part of quota structure */
9 -static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
10 +static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
11  {
12         struct mem_dqblk *dm = &dquot->dq_dqb;
13         int check_blim = 0, check_ilim = 0;
14 +       struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
15 +
16 +       if ((di->dqb_valid & QIF_BLIMITS &&
17 +            (di->dqb_bhardlimit > dqi->dqi_maxblimit ||
18 +             di->dqb_bsoftlimit > dqi->dqi_maxblimit)) ||
19 +           (di->dqb_valid & QIF_ILIMITS &&
20 +            (di->dqb_ihardlimit > dqi->dqi_maxilimit ||
21 +             di->dqb_isoftlimit > dqi->dqi_maxilimit)))
22 +               return -ERANGE;
23  
24         spin_lock(&dq_data_lock);
25         if (di->dqb_valid & QIF_SPACE) {
26 @@ -1627,7 +1636,7 @@
27                         clear_bit(DQ_BLKS_B, &dquot->dq_flags);
28                 }
29                 else if (!(di->dqb_valid & QIF_BTIME))  /* Set grace only if user hasn't provided his own... */
30 -                       dm->dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
31 +                       dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
32         }
33         if (check_ilim) {
34                 if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) {
35 @@ -1635,7 +1644,7 @@
36                         clear_bit(DQ_INODES_B, &dquot->dq_flags);
37                 }
38                 else if (!(di->dqb_valid & QIF_ITIME))  /* Set grace only if user hasn't provided his own... */
39 -                       dm->dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
40 +                       dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
41         }
42         if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit)
43                 clear_bit(DQ_FAKE_B, &dquot->dq_flags);
44 @@ -1643,21 +1652,24 @@
45                 set_bit(DQ_FAKE_B, &dquot->dq_flags);
46         spin_unlock(&dq_data_lock);
47         mark_dquot_dirty(dquot);
48 +
49 +       return 0;
50  }
51  
52  int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
53  {
54         struct dquot *dquot;
55 +       int rc;
56  
57         mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
58         if (!(dquot = dqget(sb, id, type))) {
59                 mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
60                 return -ESRCH;
61         }
62 -       do_set_dqblk(dquot, di);
63 +       rc = do_set_dqblk(dquot, di);
64         dqput(dquot);
65         mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
66 -       return 0;
67 +       return rc;
68  }
69  
70  /* Generic routine for getting common part of quota file information */
71 Index: linux-2.6.18-128.1.6/fs/quota_v1.c
72 ===================================================================
73 --- linux-2.6.18-128.1.6.orig/fs/quota_v1.c     2006-09-19 21:42:06.000000000 -0600
74 +++ linux-2.6.18-128.1.6/fs/quota_v1.c  2009-06-02 23:26:36.000000000 -0600
75 @@ -139,6 +139,9 @@
76                 goto out;
77         }
78         ret = 0;
79 +       /* limits are stored as unsigned 32-bit data */
80 +       dqopt->info[type].dqi_maxblimit = 0xffffffff;
81 +       dqopt->info[type].dqi_maxilimit = 0xffffffff;
82         dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
83         dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
84  out:
85 Index: linux-2.6.18-128.1.6/fs/quota_v2.c
86 ===================================================================
87 --- linux-2.6.18-128.1.6.orig/fs/quota_v2.c     2006-09-19 21:42:06.000000000 -0600
88 +++ linux-2.6.18-128.1.6/fs/quota_v2.c  2009-06-02 23:26:36.000000000 -0600
89 @@ -23,26 +23,64 @@
90  typedef char *dqbuf_t;
91  
92  #define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
93 -#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))
94 +#define GETENTRIES(buf) ((union v2_disk_dqblk *)(((char *)buf) + \
95 +                        sizeof(struct v2_disk_dqdbheader)))
96 +#define REV_ASSERT(r) BUG_ON((rev) != 0 && (rev) != 1)
97 +
98 +static const union v2_disk_dqblk emptydquot;
99 +static const union v2_disk_dqblk fakedquot[2] = {
100 +       {.r0 = {.dqb_itime = __constant_cpu_to_le64(1LLU)} },
101 +       {.r1 = {.dqb_itime = __constant_cpu_to_le64(1LLU)} }
102 +};
103  
104 -/* Check whether given file is really vfsv0 quotafile */
105 -static int v2_check_quota_file(struct super_block *sb, int type)
106 +static inline uint v2_dqblksz(uint rev)
107 +{
108 +       uint sz;
109 +
110 +       REV_ASSERT(rev);
111 +
112 +       if (rev == 0)
113 +               sz = sizeof(struct v2_disk_dqblk_r0);
114 +       else
115 +               sz = sizeof(struct v2_disk_dqblk_r1);
116 +
117 +       return sz;
118 +}
119 +
120 +/* Number of quota entries in a block */
121 +static inline int v2_dqstrinblk(uint rev)
122 +{
123 +       return (V2_DQBLKSIZE-sizeof(struct v2_disk_dqdbheader))/v2_dqblksz(rev);
124 +}
125 +
126 +/* Get revision of a quota file, -1 if it does not look a quota file */
127 +static int v2_quota_file_revision(struct super_block *sb, int type)
128  {
129         struct v2_disk_dqheader dqhead;
130         ssize_t size;
131         static const uint quota_magics[] = V2_INITQMAGICS;
132 -       static const uint quota_versions[] = V2_INITQVERSIONS;
133 +       static const uint quota_versions_r0[] = V2_INITQVERSIONS_R0;
134 +       static const uint quota_versions_r1[] = V2_INITQVERSIONS_R1;
135   
136         size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
137         if (size != sizeof(struct v2_disk_dqheader)) {
138                 printk("quota_v2: failed read expected=%zd got=%zd\n",
139                         sizeof(struct v2_disk_dqheader), size);
140 -               return 0;
141 +               return -1;
142         }
143 -       if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
144 -           le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
145 -               return 0;
146 -       return 1;
147 +       if (le32_to_cpu(dqhead.dqh_magic) == quota_magics[type]) {
148 +               if (le32_to_cpu(dqhead.dqh_version) == quota_versions_r0[type])
149 +                       return 0;
150 +               if (le32_to_cpu(dqhead.dqh_version) == quota_versions_r1[type])
151 +                       return 1;
152 +       }
153 +       return -1;
154 +}
155 +
156 +/* Check whether given file is really vfsv0 quotafile */
157 +static inline int v2_check_quota_file(struct super_block *sb, int type)
158 +{
159 +       return v2_quota_file_revision(sb, type) != -1;
160  }
161  
162  /* Read information header from quota file */
163 @@ -51,6 +89,13 @@
164         struct v2_disk_dqinfo dinfo;
165         struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
166         ssize_t size;
167 +       int rev;
168 +
169 +       rev = v2_quota_file_revision(sb, type);
170 +       if (rev < 0) {
171 +               printk(KERN_WARNING "Second quota file check failed.\n");
172 +               return -1;
173 +       }
174  
175         size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
176                sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
177 @@ -65,6 +110,16 @@
178         info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
179         info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
180         info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
181 +
182 +       info->u.v2_i.dqi_revision = rev;
183 +       if (rev == 0) {
184 +               info->dqi_maxblimit = 0xffffffffULL;
185 +               info->dqi_maxilimit = 0xffffffffULL;
186 +       } else {
187 +               info->dqi_maxblimit = 0xffffffffffffffffULL;
188 +               info->dqi_maxilimit = 0xffffffffffffffffULL;
189 +       }
190 +
191         return 0;
192  }
193  
194 @@ -94,29 +149,61 @@
195         return 0;
196  }
197  
198 -static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
199 +static void disk2memdqb(struct mem_dqblk *m, union v2_disk_dqblk *d, uint rev)
200  {
201 -       m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
202 -       m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
203 -       m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
204 -       m->dqb_itime = le64_to_cpu(d->dqb_itime);
205 -       m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
206 -       m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
207 -       m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
208 -       m->dqb_btime = le64_to_cpu(d->dqb_btime);
209 -}
210 -
211 -static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
212 -{
213 -       d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
214 -       d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
215 -       d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
216 -       d->dqb_itime = cpu_to_le64(m->dqb_itime);
217 -       d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
218 -       d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
219 -       d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
220 -       d->dqb_btime = cpu_to_le64(m->dqb_btime);
221 -       d->dqb_id = cpu_to_le32(id);
222 +       REV_ASSERT(rev);
223 +
224 +       if (rev == 0) {
225 +               struct v2_disk_dqblk_r0 *ddqblk = &d->r0;
226 +               m->dqb_ihardlimit = le32_to_cpu(ddqblk->dqb_ihardlimit);
227 +               m->dqb_isoftlimit = le32_to_cpu(ddqblk->dqb_isoftlimit);
228 +               m->dqb_curinodes = le32_to_cpu(ddqblk->dqb_curinodes);
229 +               m->dqb_itime = le64_to_cpu(ddqblk->dqb_itime);
230 +               m->dqb_bhardlimit = le32_to_cpu(ddqblk->dqb_bhardlimit);
231 +               m->dqb_bsoftlimit = le32_to_cpu(ddqblk->dqb_bsoftlimit);
232 +               m->dqb_curspace = le64_to_cpu(ddqblk->dqb_curspace);
233 +               m->dqb_btime = le64_to_cpu(ddqblk->dqb_btime);
234 +       } else {
235 +               struct v2_disk_dqblk_r1 *ddqblk = &d->r1;
236 +               m->dqb_ihardlimit = le64_to_cpu(ddqblk->dqb_ihardlimit);
237 +               m->dqb_isoftlimit = le64_to_cpu(ddqblk->dqb_isoftlimit);
238 +               m->dqb_curinodes = le64_to_cpu(ddqblk->dqb_curinodes);
239 +               m->dqb_itime = le64_to_cpu(ddqblk->dqb_itime);
240 +               m->dqb_bhardlimit = le64_to_cpu(ddqblk->dqb_bhardlimit);
241 +               m->dqb_bsoftlimit = le64_to_cpu(ddqblk->dqb_bsoftlimit);
242 +               m->dqb_curspace = le64_to_cpu(ddqblk->dqb_curspace);
243 +               m->dqb_btime = le64_to_cpu(ddqblk->dqb_btime);
244 +       }
245 +}
246 +
247 +static void mem2diskdqb(union v2_disk_dqblk *d, struct mem_dqblk *m,
248 +                       qid_t id, uint rev)
249 +{
250 +       REV_ASSERT(rev);
251 +
252 +       if (rev == 0) {
253 +               struct v2_disk_dqblk_r0 *ddqblk = &d->r0;
254 +               ddqblk->dqb_id = cpu_to_le32(id);
255 +               ddqblk->dqb_ihardlimit = cpu_to_le32((__u32)m->dqb_ihardlimit);
256 +               ddqblk->dqb_isoftlimit = cpu_to_le32((__u32)m->dqb_isoftlimit);
257 +               ddqblk->dqb_curinodes = cpu_to_le32((__u32)m->dqb_curinodes);
258 +               ddqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
259 +               ddqblk->dqb_bhardlimit = cpu_to_le32((__u32)m->dqb_bhardlimit);
260 +               ddqblk->dqb_bsoftlimit = cpu_to_le32((__u32)m->dqb_bsoftlimit);
261 +               ddqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
262 +               ddqblk->dqb_btime = cpu_to_le64(ddqblk->dqb_btime);
263 +       } else {
264 +               struct v2_disk_dqblk_r1 *ddqblk = &d->r1;
265 +               ddqblk->dqb_id = cpu_to_le32(id);
266 +               ddqblk->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
267 +               ddqblk->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
268 +               ddqblk->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
269 +               ddqblk->dqb_itime = cpu_to_le64(m->dqb_itime);
270 +               ddqblk->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
271 +               ddqblk->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
272 +               ddqblk->dqb_curspace = cpu_to_le64(m->dqb_curspace);
273 +               ddqblk->dqb_btime = cpu_to_le64(ddqblk->dqb_btime);
274 +       }
275  }
276  
277  static dqbuf_t getdqbuf(void)
278 @@ -268,10 +355,10 @@
279  {
280         struct super_block *sb = dquot->dq_sb;
281         struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
282 -       uint blk, i;
283 +       uint blk, i, rev = info->u.v2_i.dqi_revision;
284 +       uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
285         struct v2_disk_dqdbheader *dh;
286 -       struct v2_disk_dqblk *ddquot;
287 -       struct v2_disk_dqblk fakedquot;
288 +       union v2_disk_dqblk *ddquot;
289         dqbuf_t buf;
290  
291         *err = 0;
292 @@ -298,17 +385,18 @@
293                 info->u.v2_i.dqi_free_entry = blk;
294                 mark_info_dirty(sb, dquot->dq_type);
295         }
296 -       if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK)   /* Block will be full? */
297 +       /* Block will be full? */
298 +       if (le16_to_cpu(dh->dqdh_entries)+1 >= dqstrinblk)
299                 if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
300                         printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
301                         goto out_buf;
302                 }
303         dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
304 -       memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
305         /* Find free structure in block */
306 -       for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
307 +       for (i = 0; i < dqstrinblk && memcmp(&emptydquot, ddquot, dqblksz);
308 +            i++, ddquot = (char *)ddquot + dqblksz);
309  #ifdef __QUOTA_V2_PARANOIA
310 -       if (i == V2_DQSTRINBLK) {
311 +       if (i == dqstrinblk) {
312                 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
313                 *err = -EIO;
314                 goto out_buf;
315 @@ -318,7 +406,8 @@
316                 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
317                 goto out_buf;
318         }
319 -       dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
320 +       dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+
321 +                       ((char *)ddquot - (char *)buf);
322         freedqbuf(buf);
323         return blk;
324  out_buf:
325 @@ -392,7 +481,9 @@
326  {
327         int type = dquot->dq_type;
328         ssize_t ret;
329 -       struct v2_disk_dqblk ddquot, empty;
330 +       union v2_disk_dqblk ddquot;
331 +       uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
332 +       uint dqblksz = v2_dqblksz(rev);
333  
334         /* dq_off is guarded by dqio_mutex */
335         if (!dquot->dq_off)
336 @@ -401,18 +492,22 @@
337                         return ret;
338                 }
339         spin_lock(&dq_data_lock);
340 -       mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
341 +       mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id, rev);
342         /* Argh... We may need to write structure full of zeroes but that would be
343          * treated as an empty place by the rest of the code. Format change would
344          * be definitely cleaner but the problems probably are not worth it */
345 -       memset(&empty, 0, sizeof(struct v2_disk_dqblk));
346 -       if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
347 -               ddquot.dqb_itime = cpu_to_le64(1);
348 +       if (!memcmp(&emptydquot, &ddquot, dqblksz)) {
349 +               if (rev == 0)
350 +                       ddquot.r0.dqb_itime = cpu_to_le64(1);
351 +               else
352 +                       ddquot.r1.dqb_itime = cpu_to_le64(1);
353 +       }
354         spin_unlock(&dq_data_lock);
355         ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
356 -             (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
357 -       if (ret != sizeof(struct v2_disk_dqblk)) {
358 -               printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
359 +             (char *)&ddquot, dqblksz, dquot->dq_off);
360 +       if (ret != dqblksz) {
361 +               printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
362 +                       dquot->dq_sb->s_id);
363                 if (ret >= 0)
364                         ret = -ENOSPC;
365         }
366 @@ -431,6 +526,7 @@
367         struct v2_disk_dqdbheader *dh;
368         dqbuf_t buf = getdqbuf();
369         int ret = 0;
370 +       uint rev = sb_dqopt(sb)->info[type].u.v2_i.dqi_revision;
371  
372         if (!buf)
373                 return -ENOMEM;
374 @@ -456,8 +552,8 @@
375         }
376         else {
377                 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
378 -                 sizeof(struct v2_disk_dqblk));
379 -               if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
380 +                 v2_dqblksz(rev));
381 +               if (le16_to_cpu(dh->dqdh_entries) == v2_dqstrinblk(rev)-1) {
382                         /* Insert will write block itself */
383                         if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
384                                 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
385 @@ -529,41 +625,56 @@
386         return remove_tree(dquot, &tmp, 0);
387  }
388  
389 +static inline __u32 dqid(union v2_disk_dqblk *ddquot, uint rev)
390 +{
391 +       __u32 dq_id;
392 +
393 +       REV_ASSERT(rev);
394 +
395 +       if (rev == 0)
396 +               dq_id = le32_to_cpu(ddquot->r0.dqb_id);
397 +       else
398 +               dq_id = le32_to_cpu(ddquot->r1.dqb_id);
399 +
400 +       return dq_id;
401 +}
402 +
403  /* Find entry in block */
404  static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
405  {
406         dqbuf_t buf = getdqbuf();
407         loff_t ret = 0;
408         int i;
409 -       struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
410 +       union v2_disk_dqblk *ddquot = GETENTRIES(buf);
411 +       int type = dquot->dq_type;
412 +       uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.dqi_revision;
413 +       uint dqblksz = v2_dqblksz(rev), dqstrinblk = v2_dqstrinblk(rev);
414  
415         if (!buf)
416                 return -ENOMEM;
417 -       if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
418 +
419 +       ret = read_blk(dquot->dq_sb, type, blk, buf);
420 +       if (ret < 0) {
421                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
422                 goto out_buf;
423         }
424         if (dquot->dq_id)
425 -               for (i = 0; i < V2_DQSTRINBLK &&
426 -                    le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
427 +               for (i = 0; i < dqstrinblk && dqid(ddquot, rev) != dquot->dq_id;
428 +                    i++, ddquot = (char *)ddquot + dqblksz);
429         else {  /* ID 0 as a bit more complicated searching... */
430 -               struct v2_disk_dqblk fakedquot;
431 -
432 -               memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
433 -               for (i = 0; i < V2_DQSTRINBLK; i++)
434 -                       if (!le32_to_cpu(ddquot[i].dqb_id) &&
435 -                           memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
436 +               for (i = 0; i < dqstrinblk; i++, ddquot = (char *)ddquot+dqblksz)
437 +                       if (!dqid(ddquot, rev) &&
438 +                           memcmp(&emptydquot, ddquot, dqblksz))
439                                 break;
440         }
441 -       if (i == V2_DQSTRINBLK) {
442 +       if (i == dqstrinblk) {
443                 printk(KERN_ERR "VFS: Quota for id %u referenced "
444                   "but not present.\n", dquot->dq_id);
445                 ret = -EIO;
446                 goto out_buf;
447         }
448         else
449 -               ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
450 -                 v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
451 +               ret = (blk << V2_DQBLKSIZE_BITS)+((char *)ddquot-(char *)buf);
452  out_buf:
453         freedqbuf(buf);
454         return ret;
455 @@ -605,7 +716,7 @@
456  {
457         int type = dquot->dq_type;
458         loff_t offset;
459 -       struct v2_disk_dqblk ddquot, empty;
460 +       union v2_disk_dqblk ddquot;
461         int ret = 0;
462  
463  #ifdef __QUOTA_V2_PARANOIA
464 @@ -626,25 +737,30 @@
465                 ret = offset;
466         }
467         else {
468 +               uint rev = sb_dqopt(dquot->dq_sb)->info[type].u.v2_i.
469 +                          dqi_revision;
470 +               uint  dqblksz = v2_dqblksz(rev);
471                 dquot->dq_off = offset;
472 -               if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
473 -                   (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
474 -                   != sizeof(struct v2_disk_dqblk)) {
475 +               ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
476 +                                          (char *)&ddquot, dqblksz, offset);
477 +               if (ret != dqblksz) {
478                         if (ret >= 0)
479                                 ret = -EIO;
480                         printk(KERN_ERR "VFS: Error while reading quota "
481                           "structure for id %u.\n", dquot->dq_id);
482 -                       memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
483 +                       memset(&ddquot, 0, dqblksz);
484                 }
485                 else {
486                         ret = 0;
487                         /* We need to escape back all-zero structure */
488 -                       memset(&empty, 0, sizeof(struct v2_disk_dqblk));
489 -                       empty.dqb_itime = cpu_to_le64(1);
490 -                       if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
491 -                               ddquot.dqb_itime = 0;
492 +                       if (!memcmp(&fakedquot[rev], &ddquot, dqblksz)) {
493 +                               if (rev == 0)
494 +                                       ddquot.r0.dqb_itime = cpu_to_le64(0);
495 +                               else
496 +                                       ddquot.r1.dqb_itime = cpu_to_le64(0);
497 +                       }
498                 }
499 -               disk2memdqb(&dquot->dq_dqb, &ddquot);
500 +               disk2memdqb(&dquot->dq_dqb, &ddquot, rev);
501                 if (!dquot->dq_dqb.dqb_bhardlimit &&
502                         !dquot->dq_dqb.dqb_bsoftlimit &&
503                         !dquot->dq_dqb.dqb_ihardlimit &&
504 Index: linux-2.6.18-128.1.6/include/linux/dqblk_v2.h
505 ===================================================================
506 --- linux-2.6.18-128.1.6.orig/include/linux/dqblk_v2.h  2006-09-19 21:42:06.000000000 -0600
507 +++ linux-2.6.18-128.1.6/include/linux/dqblk_v2.h       2009-06-02 23:26:36.000000000 -0600
508 @@ -21,6 +21,7 @@
509         unsigned int dqi_blocks;
510         unsigned int dqi_free_blk;
511         unsigned int dqi_free_entry;
512 +       unsigned int dqi_revision;
513  };
514  
515  #endif /* _LINUX_DQBLK_V2_H */
516 Index: linux-2.6.18-128.1.6/include/linux/quota.h
517 ===================================================================
518 --- linux-2.6.18-128.1.6.orig/include/linux/quota.h     2006-09-19 21:42:06.000000000 -0600
519 +++ linux-2.6.18-128.1.6/include/linux/quota.h  2009-06-02 23:26:36.000000000 -0600
520 @@ -149,12 +149,12 @@
521   * Data for one user/group kept in memory
522   */
523  struct mem_dqblk {
524 -       __u32 dqb_bhardlimit;   /* absolute limit on disk blks alloc */
525 -       __u32 dqb_bsoftlimit;   /* preferred limit on disk blks */
526 +       qsize_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
527 +       qsize_t dqb_bsoftlimit; /* preferred limit on disk blks */
528         qsize_t dqb_curspace;   /* current used space */
529 -       __u32 dqb_ihardlimit;   /* absolute limit on allocated inodes */
530 -       __u32 dqb_isoftlimit;   /* preferred inode limit */
531 -       __u32 dqb_curinodes;    /* current # allocated inodes */
532 +       qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */
533 +       qsize_t dqb_isoftlimit; /* preferred inode limit */
534 +       qsize_t dqb_curinodes;  /* current # allocated inodes */
535         time_t dqb_btime;       /* time limit for excessive disk use */
536         time_t dqb_itime;       /* time limit for excessive inode use */
537  };
538 @@ -170,6 +170,8 @@
539         unsigned long dqi_flags;
540         unsigned int dqi_bgrace;
541         unsigned int dqi_igrace;
542 +       qsize_t dqi_maxblimit;
543 +       qsize_t dqi_maxilimit;
544         union {
545                 struct v1_mem_dqinfo v1_i;
546                 struct v2_mem_dqinfo v2_i;
547 Index: linux-2.6.18-128.1.6/include/linux/quotaio_v2.h
548 ===================================================================
549 --- linux-2.6.18-128.1.6.orig/include/linux/quotaio_v2.h        2006-09-19 21:42:06.000000000 -0600
550 +++ linux-2.6.18-128.1.6/include/linux/quotaio_v2.h     2009-06-02 23:26:36.000000000 -0600
551 @@ -16,28 +16,51 @@
552         0xd9c01927      /* GRPQUOTA */\
553  }
554  
555 -#define V2_INITQVERSIONS {\
556 +#define V2_INITQVERSIONS_R0 {\
557         0,              /* USRQUOTA */\
558         0               /* GRPQUOTA */\
559  }
560  
561 +#define V2_INITQVERSIONS_R1 {\
562 +       1,              /* USRQUOTA */\
563 +       1               /* GRPQUOTA */\
564 +}
565 +
566  /*
567   * The following structure defines the format of the disk quota file
568   * (as it appears on disk) - the file is a radix tree whose leaves point
569   * to blocks of these structures.
570   */
571 -struct v2_disk_dqblk {
572 +struct v2_disk_dqblk_r0 {
573         __le32 dqb_id;          /* id this quota applies to */
574         __le32 dqb_ihardlimit;  /* absolute limit on allocated inodes */
575         __le32 dqb_isoftlimit;  /* preferred inode limit */
576         __le32 dqb_curinodes;   /* current # allocated inodes */
577 -       __le32 dqb_bhardlimit;  /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
578 -       __le32 dqb_bsoftlimit;  /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
579 +       __le32 dqb_bhardlimit;  /* absolute limit on disk space */
580 +       __le32 dqb_bsoftlimit;  /* preferred limit on disk space */
581 +       __le64 dqb_curspace;    /* current space occupied (in bytes) */
582 +       __le64 dqb_btime;       /* time limit for excessive disk use */
583 +       __le64 dqb_itime;       /* time limit for excessive inode use */
584 +};
585 +
586 +struct v2_disk_dqblk_r1 {
587 +       __le32 dqb_id;          /* id this quota applies to */
588 +       __le32 dqb_padding;     /* padding field */
589 +       __le64 dqb_ihardlimit;  /* absolute limit on allocated inodes */
590 +       __le64 dqb_isoftlimit;  /* preferred inode limit */
591 +       __le64 dqb_curinodes;   /* current # allocated inodes */
592 +       __le64 dqb_bhardlimit;  /* absolute limit on disk space */
593 +       __le64 dqb_bsoftlimit;  /* preferred limit on disk space */
594         __le64 dqb_curspace;    /* current space occupied (in bytes) */
595         __le64 dqb_btime;       /* time limit for excessive disk use */
596         __le64 dqb_itime;       /* time limit for excessive inode use */
597  };
598  
599 +union v2_disk_dqblk {
600 +       struct v2_disk_dqblk_r0 r0;
601 +       struct v2_disk_dqblk_r1 r1;
602 +};
603 +
604  /*
605   * Here are header structures as written on disk and their in-memory copies
606   */
607 @@ -59,7 +82,7 @@
608  
609  /*
610   *  Structure of header of block with quota structures. It is padded to 16 bytes so
611 - *  there will be space for exactly 21 quota-entries in a block
612 + *  there will be space for exactly 21 (r0) or 14 (r1) quota-entries in a block
613   */
614  struct v2_disk_dqdbheader {
615         __le32 dqdh_next_free;  /* Number of next block with free entry */
616 @@ -74,6 +97,5 @@
617  #define V2_DQBLKSIZE   (1 << V2_DQBLKSIZE_BITS)        /* Size of block with quota structures */
618  #define V2_DQTREEOFF   1               /* Offset of tree in file in blocks */
619  #define V2_DQTREEDEPTH 4               /* Depth of quota tree */
620 -#define V2_DQSTRINBLK  ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk))     /* Number of entries in one blocks */
621  
622  #endif /* _LINUX_QUOTAIO_V2_H */