adfs: work around bogus sparse warning
[linux-2.6/openmoko-kernel/knife-kernel.git] / fs / quota_v2.c
blob23b647f25d08a405bad3ba8917d550f120d60ccf
1 /*
2 * vfsv0 quota IO operations on file
3 */
5 #include <linux/errno.h>
6 #include <linux/fs.h>
7 #include <linux/mount.h>
8 #include <linux/dqblk_v2.h>
9 #include <linux/quotaio_v2.h>
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/module.h>
13 #include <linux/slab.h>
15 #include <asm/byteorder.h>
17 MODULE_AUTHOR("Jan Kara");
18 MODULE_DESCRIPTION("Quota format v2 support");
19 MODULE_LICENSE("GPL");
21 #define __QUOTA_V2_PARANOIA
23 typedef char *dqbuf_t;
25 #define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
26 #define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))
28 /* Check whether given file is really vfsv0 quotafile */
29 static int v2_check_quota_file(struct super_block *sb, int type)
31 struct v2_disk_dqheader dqhead;
32 ssize_t size;
33 static const uint quota_magics[] = V2_INITQMAGICS;
34 static const uint quota_versions[] = V2_INITQVERSIONS;
36 size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
37 if (size != sizeof(struct v2_disk_dqheader)) {
38 printk("quota_v2: failed read expected=%zd got=%zd\n",
39 sizeof(struct v2_disk_dqheader), size);
40 return 0;
42 if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
43 le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
44 return 0;
45 return 1;
48 /* Read information header from quota file */
49 static int v2_read_file_info(struct super_block *sb, int type)
51 struct v2_disk_dqinfo dinfo;
52 struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
53 ssize_t size;
55 size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
56 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
57 if (size != sizeof(struct v2_disk_dqinfo)) {
58 printk(KERN_WARNING "Can't read info structure on device %s.\n",
59 sb->s_id);
60 return -1;
62 /* limits are stored as unsigned 32-bit data */
63 info->dqi_maxblimit = 0xffffffff;
64 info->dqi_maxilimit = 0xffffffff;
65 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
66 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
67 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
68 info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
69 info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
70 info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
71 return 0;
74 /* Write information header to quota file */
75 static int v2_write_file_info(struct super_block *sb, int type)
77 struct v2_disk_dqinfo dinfo;
78 struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
79 ssize_t size;
81 spin_lock(&dq_data_lock);
82 info->dqi_flags &= ~DQF_INFO_DIRTY;
83 dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
84 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
85 dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
86 spin_unlock(&dq_data_lock);
87 dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
88 dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
89 dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
90 size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
91 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
92 if (size != sizeof(struct v2_disk_dqinfo)) {
93 printk(KERN_WARNING "Can't write info structure on device %s.\n",
94 sb->s_id);
95 return -1;
97 return 0;
100 static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
102 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
103 m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
104 m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
105 m->dqb_itime = le64_to_cpu(d->dqb_itime);
106 m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
107 m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
108 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
109 m->dqb_btime = le64_to_cpu(d->dqb_btime);
112 static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
114 d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
115 d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
116 d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
117 d->dqb_itime = cpu_to_le64(m->dqb_itime);
118 d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
119 d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
120 d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
121 d->dqb_btime = cpu_to_le64(m->dqb_btime);
122 d->dqb_id = cpu_to_le32(id);
125 static dqbuf_t getdqbuf(void)
127 dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_NOFS);
128 if (!buf)
129 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
130 return buf;
133 static inline void freedqbuf(dqbuf_t buf)
135 kfree(buf);
138 static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
140 memset(buf, 0, V2_DQBLKSIZE);
141 return sb->s_op->quota_read(sb, type, (char *)buf,
142 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
145 static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
147 return sb->s_op->quota_write(sb, type, (char *)buf,
148 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
151 /* Remove empty block from list and return it */
152 static int get_free_dqblk(struct super_block *sb, int type)
154 dqbuf_t buf = getdqbuf();
155 struct mem_dqinfo *info = sb_dqinfo(sb, type);
156 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
157 int ret, blk;
159 if (!buf)
160 return -ENOMEM;
161 if (info->u.v2_i.dqi_free_blk) {
162 blk = info->u.v2_i.dqi_free_blk;
163 if ((ret = read_blk(sb, type, blk, buf)) < 0)
164 goto out_buf;
165 info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
167 else {
168 memset(buf, 0, V2_DQBLKSIZE);
169 /* Assure block allocation... */
170 if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0)
171 goto out_buf;
172 blk = info->u.v2_i.dqi_blocks++;
174 mark_info_dirty(sb, type);
175 ret = blk;
176 out_buf:
177 freedqbuf(buf);
178 return ret;
181 /* Insert empty block to the list */
182 static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
184 struct mem_dqinfo *info = sb_dqinfo(sb, type);
185 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
186 int err;
188 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk);
189 dh->dqdh_prev_free = cpu_to_le32(0);
190 dh->dqdh_entries = cpu_to_le16(0);
191 info->u.v2_i.dqi_free_blk = blk;
192 mark_info_dirty(sb, type);
193 /* Some strange block. We had better leave it... */
194 if ((err = write_blk(sb, type, blk, buf)) < 0)
195 return err;
196 return 0;
199 /* Remove given block from the list of blocks with free entries */
200 static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
202 dqbuf_t tmpbuf = getdqbuf();
203 struct mem_dqinfo *info = sb_dqinfo(sb, type);
204 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
205 uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
206 int err;
208 if (!tmpbuf)
209 return -ENOMEM;
210 if (nextblk) {
211 if ((err = read_blk(sb, type, nextblk, tmpbuf)) < 0)
212 goto out_buf;
213 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
214 if ((err = write_blk(sb, type, nextblk, tmpbuf)) < 0)
215 goto out_buf;
217 if (prevblk) {
218 if ((err = read_blk(sb, type, prevblk, tmpbuf)) < 0)
219 goto out_buf;
220 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
221 if ((err = write_blk(sb, type, prevblk, tmpbuf)) < 0)
222 goto out_buf;
224 else {
225 info->u.v2_i.dqi_free_entry = nextblk;
226 mark_info_dirty(sb, type);
228 freedqbuf(tmpbuf);
229 dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
230 /* No matter whether write succeeds block is out of list */
231 if (write_blk(sb, type, blk, buf) < 0)
232 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
233 return 0;
234 out_buf:
235 freedqbuf(tmpbuf);
236 return err;
239 /* Insert given block to the beginning of list with free entries */
240 static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
242 dqbuf_t tmpbuf = getdqbuf();
243 struct mem_dqinfo *info = sb_dqinfo(sb, type);
244 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
245 int err;
247 if (!tmpbuf)
248 return -ENOMEM;
249 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
250 dh->dqdh_prev_free = cpu_to_le32(0);
251 if ((err = write_blk(sb, type, blk, buf)) < 0)
252 goto out_buf;
253 if (info->u.v2_i.dqi_free_entry) {
254 if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
255 goto out_buf;
256 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
257 if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
258 goto out_buf;
260 freedqbuf(tmpbuf);
261 info->u.v2_i.dqi_free_entry = blk;
262 mark_info_dirty(sb, type);
263 return 0;
264 out_buf:
265 freedqbuf(tmpbuf);
266 return err;
269 /* Find space for dquot */
270 static uint find_free_dqentry(struct dquot *dquot, int *err)
272 struct super_block *sb = dquot->dq_sb;
273 struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
274 uint blk, i;
275 struct v2_disk_dqdbheader *dh;
276 struct v2_disk_dqblk *ddquot;
277 struct v2_disk_dqblk fakedquot;
278 dqbuf_t buf;
280 *err = 0;
281 if (!(buf = getdqbuf())) {
282 *err = -ENOMEM;
283 return 0;
285 dh = (struct v2_disk_dqdbheader *)buf;
286 ddquot = GETENTRIES(buf);
287 if (info->u.v2_i.dqi_free_entry) {
288 blk = info->u.v2_i.dqi_free_entry;
289 if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0)
290 goto out_buf;
292 else {
293 blk = get_free_dqblk(sb, dquot->dq_type);
294 if ((int)blk < 0) {
295 *err = blk;
296 freedqbuf(buf);
297 return 0;
299 memset(buf, 0, V2_DQBLKSIZE);
300 /* This is enough as block is already zeroed and entry list is empty... */
301 info->u.v2_i.dqi_free_entry = blk;
302 mark_info_dirty(sb, dquot->dq_type);
304 if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */
305 if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
306 printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
307 goto out_buf;
309 dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
310 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
311 /* Find free structure in block */
312 for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
313 #ifdef __QUOTA_V2_PARANOIA
314 if (i == V2_DQSTRINBLK) {
315 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
316 *err = -EIO;
317 goto out_buf;
319 #endif
320 if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) {
321 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
322 goto out_buf;
324 dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
325 freedqbuf(buf);
326 return blk;
327 out_buf:
328 freedqbuf(buf);
329 return 0;
332 /* Insert reference to structure into the trie */
333 static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
335 struct super_block *sb = dquot->dq_sb;
336 dqbuf_t buf;
337 int ret = 0, newson = 0, newact = 0;
338 __le32 *ref;
339 uint newblk;
341 if (!(buf = getdqbuf()))
342 return -ENOMEM;
343 if (!*treeblk) {
344 ret = get_free_dqblk(sb, dquot->dq_type);
345 if (ret < 0)
346 goto out_buf;
347 *treeblk = ret;
348 memset(buf, 0, V2_DQBLKSIZE);
349 newact = 1;
351 else {
352 if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) {
353 printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
354 goto out_buf;
357 ref = (__le32 *)buf;
358 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
359 if (!newblk)
360 newson = 1;
361 if (depth == V2_DQTREEDEPTH-1) {
362 #ifdef __QUOTA_V2_PARANOIA
363 if (newblk) {
364 printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]));
365 ret = -EIO;
366 goto out_buf;
368 #endif
369 newblk = find_free_dqentry(dquot, &ret);
371 else
372 ret = do_insert_tree(dquot, &newblk, depth+1);
373 if (newson && ret >= 0) {
374 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
375 ret = write_blk(sb, dquot->dq_type, *treeblk, buf);
377 else if (newact && ret < 0)
378 put_free_dqblk(sb, dquot->dq_type, buf, *treeblk);
379 out_buf:
380 freedqbuf(buf);
381 return ret;
384 /* Wrapper for inserting quota structure into tree */
385 static inline int dq_insert_tree(struct dquot *dquot)
387 int tmp = V2_DQTREEOFF;
388 return do_insert_tree(dquot, &tmp, 0);
392 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
394 static int v2_write_dquot(struct dquot *dquot)
396 int type = dquot->dq_type;
397 ssize_t ret;
398 struct v2_disk_dqblk ddquot, empty;
400 /* dq_off is guarded by dqio_mutex */
401 if (!dquot->dq_off)
402 if ((ret = dq_insert_tree(dquot)) < 0) {
403 printk(KERN_ERR "VFS: Error %zd occurred while creating quota.\n", ret);
404 return ret;
406 spin_lock(&dq_data_lock);
407 mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
408 /* Argh... We may need to write structure full of zeroes but that would be
409 * treated as an empty place by the rest of the code. Format change would
410 * be definitely cleaner but the problems probably are not worth it */
411 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
412 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
413 ddquot.dqb_itime = cpu_to_le64(1);
414 spin_unlock(&dq_data_lock);
415 ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
416 (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
417 if (ret != sizeof(struct v2_disk_dqblk)) {
418 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
419 if (ret >= 0)
420 ret = -ENOSPC;
422 else
423 ret = 0;
424 dqstats.writes++;
426 return ret;
429 /* Free dquot entry in data block */
430 static int free_dqentry(struct dquot *dquot, uint blk)
432 struct super_block *sb = dquot->dq_sb;
433 int type = dquot->dq_type;
434 struct v2_disk_dqdbheader *dh;
435 dqbuf_t buf = getdqbuf();
436 int ret = 0;
438 if (!buf)
439 return -ENOMEM;
440 if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
441 printk(KERN_ERR "VFS: Quota structure has offset to other "
442 "block (%u) than it should (%u).\n", blk,
443 (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
444 goto out_buf;
446 if ((ret = read_blk(sb, type, blk, buf)) < 0) {
447 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
448 goto out_buf;
450 dh = (struct v2_disk_dqdbheader *)buf;
451 dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
452 if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
453 if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||
454 (ret = put_free_dqblk(sb, type, buf, blk)) < 0) {
455 printk(KERN_ERR "VFS: Can't move quota data block (%u) "
456 "to free list.\n", blk);
457 goto out_buf;
460 else {
461 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
462 sizeof(struct v2_disk_dqblk));
463 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
464 /* Insert will write block itself */
465 if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
466 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
467 goto out_buf;
470 else
471 if ((ret = write_blk(sb, type, blk, buf)) < 0) {
472 printk(KERN_ERR "VFS: Can't write quota data "
473 "block %u\n", blk);
474 goto out_buf;
477 dquot->dq_off = 0; /* Quota is now unattached */
478 out_buf:
479 freedqbuf(buf);
480 return ret;
483 /* Remove reference to dquot from tree */
484 static int remove_tree(struct dquot *dquot, uint *blk, int depth)
486 struct super_block *sb = dquot->dq_sb;
487 int type = dquot->dq_type;
488 dqbuf_t buf = getdqbuf();
489 int ret = 0;
490 uint newblk;
491 __le32 *ref = (__le32 *)buf;
493 if (!buf)
494 return -ENOMEM;
495 if ((ret = read_blk(sb, type, *blk, buf)) < 0) {
496 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
497 goto out_buf;
499 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
500 if (depth == V2_DQTREEDEPTH-1) {
501 ret = free_dqentry(dquot, newblk);
502 newblk = 0;
504 else
505 ret = remove_tree(dquot, &newblk, depth+1);
506 if (ret >= 0 && !newblk) {
507 int i;
508 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
509 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */
510 /* Don't put the root block into the free block list */
511 if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) {
512 put_free_dqblk(sb, type, buf, *blk);
513 *blk = 0;
515 else
516 if ((ret = write_blk(sb, type, *blk, buf)) < 0)
517 printk(KERN_ERR "VFS: Can't write quota tree "
518 "block %u.\n", *blk);
520 out_buf:
521 freedqbuf(buf);
522 return ret;
525 /* Delete dquot from tree */
526 static int v2_delete_dquot(struct dquot *dquot)
528 uint tmp = V2_DQTREEOFF;
530 if (!dquot->dq_off) /* Even not allocated? */
531 return 0;
532 return remove_tree(dquot, &tmp, 0);
535 /* Find entry in block */
536 static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
538 dqbuf_t buf = getdqbuf();
539 loff_t ret = 0;
540 int i;
541 struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
543 if (!buf)
544 return -ENOMEM;
545 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
546 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
547 goto out_buf;
549 if (dquot->dq_id)
550 for (i = 0; i < V2_DQSTRINBLK &&
551 le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
552 else { /* ID 0 as a bit more complicated searching... */
553 struct v2_disk_dqblk fakedquot;
555 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
556 for (i = 0; i < V2_DQSTRINBLK; i++)
557 if (!le32_to_cpu(ddquot[i].dqb_id) &&
558 memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
559 break;
561 if (i == V2_DQSTRINBLK) {
562 printk(KERN_ERR "VFS: Quota for id %u referenced "
563 "but not present.\n", dquot->dq_id);
564 ret = -EIO;
565 goto out_buf;
567 else
568 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
569 v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
570 out_buf:
571 freedqbuf(buf);
572 return ret;
575 /* Find entry for given id in the tree */
576 static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
578 dqbuf_t buf = getdqbuf();
579 loff_t ret = 0;
580 __le32 *ref = (__le32 *)buf;
582 if (!buf)
583 return -ENOMEM;
584 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
585 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
586 goto out_buf;
588 ret = 0;
589 blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
590 if (!blk) /* No reference? */
591 goto out_buf;
592 if (depth < V2_DQTREEDEPTH-1)
593 ret = find_tree_dqentry(dquot, blk, depth+1);
594 else
595 ret = find_block_dqentry(dquot, blk);
596 out_buf:
597 freedqbuf(buf);
598 return ret;
601 /* Find entry for given id in the tree - wrapper function */
602 static inline loff_t find_dqentry(struct dquot *dquot)
604 return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
607 static int v2_read_dquot(struct dquot *dquot)
609 int type = dquot->dq_type;
610 loff_t offset;
611 struct v2_disk_dqblk ddquot, empty;
612 int ret = 0;
614 #ifdef __QUOTA_V2_PARANOIA
615 /* Invalidated quota? */
616 if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) {
617 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
618 return -EIO;
620 #endif
621 offset = find_dqentry(dquot);
622 if (offset <= 0) { /* Entry not present? */
623 if (offset < 0)
624 printk(KERN_ERR "VFS: Can't read quota "
625 "structure for id %u.\n", dquot->dq_id);
626 dquot->dq_off = 0;
627 set_bit(DQ_FAKE_B, &dquot->dq_flags);
628 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
629 ret = offset;
631 else {
632 dquot->dq_off = offset;
633 if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
634 (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
635 != sizeof(struct v2_disk_dqblk)) {
636 if (ret >= 0)
637 ret = -EIO;
638 printk(KERN_ERR "VFS: Error while reading quota "
639 "structure for id %u.\n", dquot->dq_id);
640 memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
642 else {
643 ret = 0;
644 /* We need to escape back all-zero structure */
645 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
646 empty.dqb_itime = cpu_to_le64(1);
647 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
648 ddquot.dqb_itime = 0;
650 disk2memdqb(&dquot->dq_dqb, &ddquot);
651 if (!dquot->dq_dqb.dqb_bhardlimit &&
652 !dquot->dq_dqb.dqb_bsoftlimit &&
653 !dquot->dq_dqb.dqb_ihardlimit &&
654 !dquot->dq_dqb.dqb_isoftlimit)
655 set_bit(DQ_FAKE_B, &dquot->dq_flags);
657 dqstats.reads++;
659 return ret;
662 /* Check whether dquot should not be deleted. We know we are
663 * the only one operating on dquot (thanks to dq_lock) */
664 static int v2_release_dquot(struct dquot *dquot)
666 if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
667 return v2_delete_dquot(dquot);
668 return 0;
671 static struct quota_format_ops v2_format_ops = {
672 .check_quota_file = v2_check_quota_file,
673 .read_file_info = v2_read_file_info,
674 .write_file_info = v2_write_file_info,
675 .free_file_info = NULL,
676 .read_dqblk = v2_read_dquot,
677 .commit_dqblk = v2_write_dquot,
678 .release_dqblk = v2_release_dquot,
681 static struct quota_format_type v2_quota_format = {
682 .qf_fmt_id = QFMT_VFS_V0,
683 .qf_ops = &v2_format_ops,
684 .qf_owner = THIS_MODULE
687 static int __init init_v2_quota_format(void)
689 return register_quota_format(&v2_quota_format);
692 static void __exit exit_v2_quota_format(void)
694 unregister_quota_format(&v2_quota_format);
697 module_init(init_v2_quota_format);
698 module_exit(exit_v2_quota_format);