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