[ARM] 5348/1: fix documentation wrt location of the alignment trap interface
[linux-2.6/mini2440.git] / fs / quota_v2.c
blobb53827dc02d9081c50e0d0ed0acb971c2ad931b8
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>
14 #include <linux/quotaops.h>
16 #include <asm/byteorder.h>
18 MODULE_AUTHOR("Jan Kara");
19 MODULE_DESCRIPTION("Quota format v2 support");
20 MODULE_LICENSE("GPL");
22 #define __QUOTA_V2_PARANOIA
24 typedef char *dqbuf_t;
26 #define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
27 #define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))
29 /* Check whether given file is really vfsv0 quotafile */
30 static int v2_check_quota_file(struct super_block *sb, int type)
32 struct v2_disk_dqheader dqhead;
33 ssize_t size;
34 static const uint quota_magics[] = V2_INITQMAGICS;
35 static const uint quota_versions[] = V2_INITQVERSIONS;
37 size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
38 if (size != sizeof(struct v2_disk_dqheader)) {
39 printk("quota_v2: failed read expected=%zd got=%zd\n",
40 sizeof(struct v2_disk_dqheader), size);
41 return 0;
43 if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
44 le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
45 return 0;
46 return 1;
49 /* Read information header from quota file */
50 static int v2_read_file_info(struct super_block *sb, int type)
52 struct v2_disk_dqinfo dinfo;
53 struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
54 ssize_t size;
56 size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
57 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
58 if (size != sizeof(struct v2_disk_dqinfo)) {
59 printk(KERN_WARNING "Can't read info structure on device %s.\n",
60 sb->s_id);
61 return -1;
63 /* limits are stored as unsigned 32-bit data */
64 info->dqi_maxblimit = 0xffffffff;
65 info->dqi_maxilimit = 0xffffffff;
66 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
67 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
68 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
69 info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
70 info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
71 info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
72 return 0;
75 /* Write information header to quota file */
76 static int v2_write_file_info(struct super_block *sb, int type)
78 struct v2_disk_dqinfo dinfo;
79 struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
80 ssize_t size;
82 spin_lock(&dq_data_lock);
83 info->dqi_flags &= ~DQF_INFO_DIRTY;
84 dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
85 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
86 dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
87 spin_unlock(&dq_data_lock);
88 dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
89 dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
90 dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
91 size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
92 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
93 if (size != sizeof(struct v2_disk_dqinfo)) {
94 printk(KERN_WARNING "Can't write info structure on device %s.\n",
95 sb->s_id);
96 return -1;
98 return 0;
101 static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
103 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
104 m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
105 m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
106 m->dqb_itime = le64_to_cpu(d->dqb_itime);
107 m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
108 m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
109 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
110 m->dqb_btime = le64_to_cpu(d->dqb_btime);
113 static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
115 d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
116 d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
117 d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
118 d->dqb_itime = cpu_to_le64(m->dqb_itime);
119 d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
120 d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
121 d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
122 d->dqb_btime = cpu_to_le64(m->dqb_btime);
123 d->dqb_id = cpu_to_le32(id);
126 static dqbuf_t getdqbuf(void)
128 dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_NOFS);
129 if (!buf)
130 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
131 return buf;
134 static inline void freedqbuf(dqbuf_t buf)
136 kfree(buf);
139 static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
141 memset(buf, 0, V2_DQBLKSIZE);
142 return sb->s_op->quota_read(sb, type, (char *)buf,
143 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
146 static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
148 return sb->s_op->quota_write(sb, type, (char *)buf,
149 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
152 /* Remove empty block from list and return it */
153 static int get_free_dqblk(struct super_block *sb, int type)
155 dqbuf_t buf = getdqbuf();
156 struct mem_dqinfo *info = sb_dqinfo(sb, type);
157 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
158 int ret, blk;
160 if (!buf)
161 return -ENOMEM;
162 if (info->u.v2_i.dqi_free_blk) {
163 blk = info->u.v2_i.dqi_free_blk;
164 if ((ret = read_blk(sb, type, blk, buf)) < 0)
165 goto out_buf;
166 info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
168 else {
169 memset(buf, 0, V2_DQBLKSIZE);
170 /* Assure block allocation... */
171 if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0)
172 goto out_buf;
173 blk = info->u.v2_i.dqi_blocks++;
175 mark_info_dirty(sb, type);
176 ret = blk;
177 out_buf:
178 freedqbuf(buf);
179 return ret;
182 /* Insert empty block to the list */
183 static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
185 struct mem_dqinfo *info = sb_dqinfo(sb, type);
186 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
187 int err;
189 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk);
190 dh->dqdh_prev_free = cpu_to_le32(0);
191 dh->dqdh_entries = cpu_to_le16(0);
192 info->u.v2_i.dqi_free_blk = blk;
193 mark_info_dirty(sb, type);
194 /* Some strange block. We had better leave it... */
195 if ((err = write_blk(sb, type, blk, buf)) < 0)
196 return err;
197 return 0;
200 /* Remove given block from the list of blocks with free entries */
201 static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
203 dqbuf_t tmpbuf = getdqbuf();
204 struct mem_dqinfo *info = sb_dqinfo(sb, type);
205 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
206 uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
207 int err;
209 if (!tmpbuf)
210 return -ENOMEM;
211 if (nextblk) {
212 if ((err = read_blk(sb, type, nextblk, tmpbuf)) < 0)
213 goto out_buf;
214 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
215 if ((err = write_blk(sb, type, nextblk, tmpbuf)) < 0)
216 goto out_buf;
218 if (prevblk) {
219 if ((err = read_blk(sb, type, prevblk, tmpbuf)) < 0)
220 goto out_buf;
221 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
222 if ((err = write_blk(sb, type, prevblk, tmpbuf)) < 0)
223 goto out_buf;
225 else {
226 info->u.v2_i.dqi_free_entry = nextblk;
227 mark_info_dirty(sb, type);
229 freedqbuf(tmpbuf);
230 dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
231 /* No matter whether write succeeds block is out of list */
232 if (write_blk(sb, type, blk, buf) < 0)
233 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
234 return 0;
235 out_buf:
236 freedqbuf(tmpbuf);
237 return err;
240 /* Insert given block to the beginning of list with free entries */
241 static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
243 dqbuf_t tmpbuf = getdqbuf();
244 struct mem_dqinfo *info = sb_dqinfo(sb, type);
245 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
246 int err;
248 if (!tmpbuf)
249 return -ENOMEM;
250 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
251 dh->dqdh_prev_free = cpu_to_le32(0);
252 if ((err = write_blk(sb, type, blk, buf)) < 0)
253 goto out_buf;
254 if (info->u.v2_i.dqi_free_entry) {
255 if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
256 goto out_buf;
257 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
258 if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
259 goto out_buf;
261 freedqbuf(tmpbuf);
262 info->u.v2_i.dqi_free_entry = blk;
263 mark_info_dirty(sb, type);
264 return 0;
265 out_buf:
266 freedqbuf(tmpbuf);
267 return err;
270 /* Find space for dquot */
271 static uint find_free_dqentry(struct dquot *dquot, int *err)
273 struct super_block *sb = dquot->dq_sb;
274 struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
275 uint blk, i;
276 struct v2_disk_dqdbheader *dh;
277 struct v2_disk_dqblk *ddquot;
278 struct v2_disk_dqblk fakedquot;
279 dqbuf_t buf;
281 *err = 0;
282 if (!(buf = getdqbuf())) {
283 *err = -ENOMEM;
284 return 0;
286 dh = (struct v2_disk_dqdbheader *)buf;
287 ddquot = GETENTRIES(buf);
288 if (info->u.v2_i.dqi_free_entry) {
289 blk = info->u.v2_i.dqi_free_entry;
290 if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0)
291 goto out_buf;
293 else {
294 blk = get_free_dqblk(sb, dquot->dq_type);
295 if ((int)blk < 0) {
296 *err = blk;
297 freedqbuf(buf);
298 return 0;
300 memset(buf, 0, V2_DQBLKSIZE);
301 /* This is enough as block is already zeroed and entry list is empty... */
302 info->u.v2_i.dqi_free_entry = blk;
303 mark_info_dirty(sb, dquot->dq_type);
305 if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */
306 if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
307 printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
308 goto out_buf;
310 le16_add_cpu(&dh->dqdh_entries, 1);
311 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
312 /* Find free structure in block */
313 for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
314 #ifdef __QUOTA_V2_PARANOIA
315 if (i == V2_DQSTRINBLK) {
316 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
317 *err = -EIO;
318 goto out_buf;
320 #endif
321 if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) {
322 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
323 goto out_buf;
325 dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
326 freedqbuf(buf);
327 return blk;
328 out_buf:
329 freedqbuf(buf);
330 return 0;
333 /* Insert reference to structure into the trie */
334 static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
336 struct super_block *sb = dquot->dq_sb;
337 dqbuf_t buf;
338 int ret = 0, newson = 0, newact = 0;
339 __le32 *ref;
340 uint newblk;
342 if (!(buf = getdqbuf()))
343 return -ENOMEM;
344 if (!*treeblk) {
345 ret = get_free_dqblk(sb, dquot->dq_type);
346 if (ret < 0)
347 goto out_buf;
348 *treeblk = ret;
349 memset(buf, 0, V2_DQBLKSIZE);
350 newact = 1;
352 else {
353 if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) {
354 printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
355 goto out_buf;
358 ref = (__le32 *)buf;
359 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
360 if (!newblk)
361 newson = 1;
362 if (depth == V2_DQTREEDEPTH-1) {
363 #ifdef __QUOTA_V2_PARANOIA
364 if (newblk) {
365 printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]));
366 ret = -EIO;
367 goto out_buf;
369 #endif
370 newblk = find_free_dqentry(dquot, &ret);
372 else
373 ret = do_insert_tree(dquot, &newblk, depth+1);
374 if (newson && ret >= 0) {
375 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
376 ret = write_blk(sb, dquot->dq_type, *treeblk, buf);
378 else if (newact && ret < 0)
379 put_free_dqblk(sb, dquot->dq_type, buf, *treeblk);
380 out_buf:
381 freedqbuf(buf);
382 return ret;
385 /* Wrapper for inserting quota structure into tree */
386 static inline int dq_insert_tree(struct dquot *dquot)
388 int tmp = V2_DQTREEOFF;
389 return do_insert_tree(dquot, &tmp, 0);
393 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
395 static int v2_write_dquot(struct dquot *dquot)
397 int type = dquot->dq_type;
398 ssize_t ret;
399 struct v2_disk_dqblk ddquot, empty;
401 /* dq_off is guarded by dqio_mutex */
402 if (!dquot->dq_off)
403 if ((ret = dq_insert_tree(dquot)) < 0) {
404 printk(KERN_ERR "VFS: Error %zd occurred while creating quota.\n", ret);
405 return ret;
407 spin_lock(&dq_data_lock);
408 mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
409 /* Argh... We may need to write structure full of zeroes but that would be
410 * treated as an empty place by the rest of the code. Format change would
411 * be definitely cleaner but the problems probably are not worth it */
412 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
413 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
414 ddquot.dqb_itime = cpu_to_le64(1);
415 spin_unlock(&dq_data_lock);
416 ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
417 (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
418 if (ret != sizeof(struct v2_disk_dqblk)) {
419 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
420 if (ret >= 0)
421 ret = -ENOSPC;
423 else
424 ret = 0;
425 dqstats.writes++;
427 return ret;
430 /* Free dquot entry in data block */
431 static int free_dqentry(struct dquot *dquot, uint blk)
433 struct super_block *sb = dquot->dq_sb;
434 int type = dquot->dq_type;
435 struct v2_disk_dqdbheader *dh;
436 dqbuf_t buf = getdqbuf();
437 int ret = 0;
439 if (!buf)
440 return -ENOMEM;
441 if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
442 printk(KERN_ERR "VFS: Quota structure has offset to other "
443 "block (%u) than it should (%u).\n", blk,
444 (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
445 goto out_buf;
447 if ((ret = read_blk(sb, type, blk, buf)) < 0) {
448 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
449 goto out_buf;
451 dh = (struct v2_disk_dqdbheader *)buf;
452 le16_add_cpu(&dh->dqdh_entries, -1);
453 if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
454 if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||
455 (ret = put_free_dqblk(sb, type, buf, blk)) < 0) {
456 printk(KERN_ERR "VFS: Can't move quota data block (%u) "
457 "to free list.\n", blk);
458 goto out_buf;
461 else {
462 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
463 sizeof(struct v2_disk_dqblk));
464 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
465 /* Insert will write block itself */
466 if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
467 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
468 goto out_buf;
471 else
472 if ((ret = write_blk(sb, type, blk, buf)) < 0) {
473 printk(KERN_ERR "VFS: Can't write quota data "
474 "block %u\n", blk);
475 goto out_buf;
478 dquot->dq_off = 0; /* Quota is now unattached */
479 out_buf:
480 freedqbuf(buf);
481 return ret;
484 /* Remove reference to dquot from tree */
485 static int remove_tree(struct dquot *dquot, uint *blk, int depth)
487 struct super_block *sb = dquot->dq_sb;
488 int type = dquot->dq_type;
489 dqbuf_t buf = getdqbuf();
490 int ret = 0;
491 uint newblk;
492 __le32 *ref = (__le32 *)buf;
494 if (!buf)
495 return -ENOMEM;
496 if ((ret = read_blk(sb, type, *blk, buf)) < 0) {
497 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
498 goto out_buf;
500 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
501 if (depth == V2_DQTREEDEPTH-1) {
502 ret = free_dqentry(dquot, newblk);
503 newblk = 0;
505 else
506 ret = remove_tree(dquot, &newblk, depth+1);
507 if (ret >= 0 && !newblk) {
508 int i;
509 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
510 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */
511 /* Don't put the root block into the free block list */
512 if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) {
513 put_free_dqblk(sb, type, buf, *blk);
514 *blk = 0;
516 else
517 if ((ret = write_blk(sb, type, *blk, buf)) < 0)
518 printk(KERN_ERR "VFS: Can't write quota tree "
519 "block %u.\n", *blk);
521 out_buf:
522 freedqbuf(buf);
523 return ret;
526 /* Delete dquot from tree */
527 static int v2_delete_dquot(struct dquot *dquot)
529 uint tmp = V2_DQTREEOFF;
531 if (!dquot->dq_off) /* Even not allocated? */
532 return 0;
533 return remove_tree(dquot, &tmp, 0);
536 /* Find entry in block */
537 static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
539 dqbuf_t buf = getdqbuf();
540 loff_t ret = 0;
541 int i;
542 struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
544 if (!buf)
545 return -ENOMEM;
546 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
547 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
548 goto out_buf;
550 if (dquot->dq_id)
551 for (i = 0; i < V2_DQSTRINBLK &&
552 le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
553 else { /* ID 0 as a bit more complicated searching... */
554 struct v2_disk_dqblk fakedquot;
556 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
557 for (i = 0; i < V2_DQSTRINBLK; i++)
558 if (!le32_to_cpu(ddquot[i].dqb_id) &&
559 memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
560 break;
562 if (i == V2_DQSTRINBLK) {
563 printk(KERN_ERR "VFS: Quota for id %u referenced "
564 "but not present.\n", dquot->dq_id);
565 ret = -EIO;
566 goto out_buf;
568 else
569 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
570 v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
571 out_buf:
572 freedqbuf(buf);
573 return ret;
576 /* Find entry for given id in the tree */
577 static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
579 dqbuf_t buf = getdqbuf();
580 loff_t ret = 0;
581 __le32 *ref = (__le32 *)buf;
583 if (!buf)
584 return -ENOMEM;
585 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
586 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
587 goto out_buf;
589 ret = 0;
590 blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
591 if (!blk) /* No reference? */
592 goto out_buf;
593 if (depth < V2_DQTREEDEPTH-1)
594 ret = find_tree_dqentry(dquot, blk, depth+1);
595 else
596 ret = find_block_dqentry(dquot, blk);
597 out_buf:
598 freedqbuf(buf);
599 return ret;
602 /* Find entry for given id in the tree - wrapper function */
603 static inline loff_t find_dqentry(struct dquot *dquot)
605 return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
608 static int v2_read_dquot(struct dquot *dquot)
610 int type = dquot->dq_type;
611 loff_t offset;
612 struct v2_disk_dqblk ddquot, empty;
613 int ret = 0;
615 #ifdef __QUOTA_V2_PARANOIA
616 /* Invalidated quota? */
617 if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) {
618 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
619 return -EIO;
621 #endif
622 offset = find_dqentry(dquot);
623 if (offset <= 0) { /* Entry not present? */
624 if (offset < 0)
625 printk(KERN_ERR "VFS: Can't read quota "
626 "structure for id %u.\n", dquot->dq_id);
627 dquot->dq_off = 0;
628 set_bit(DQ_FAKE_B, &dquot->dq_flags);
629 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
630 ret = offset;
632 else {
633 dquot->dq_off = offset;
634 if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
635 (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
636 != sizeof(struct v2_disk_dqblk)) {
637 if (ret >= 0)
638 ret = -EIO;
639 printk(KERN_ERR "VFS: Error while reading quota "
640 "structure for id %u.\n", dquot->dq_id);
641 memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
643 else {
644 ret = 0;
645 /* We need to escape back all-zero structure */
646 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
647 empty.dqb_itime = cpu_to_le64(1);
648 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
649 ddquot.dqb_itime = 0;
651 disk2memdqb(&dquot->dq_dqb, &ddquot);
652 if (!dquot->dq_dqb.dqb_bhardlimit &&
653 !dquot->dq_dqb.dqb_bsoftlimit &&
654 !dquot->dq_dqb.dqb_ihardlimit &&
655 !dquot->dq_dqb.dqb_isoftlimit)
656 set_bit(DQ_FAKE_B, &dquot->dq_flags);
658 dqstats.reads++;
660 return ret;
663 /* Check whether dquot should not be deleted. We know we are
664 * the only one operating on dquot (thanks to dq_lock) */
665 static int v2_release_dquot(struct dquot *dquot)
667 if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
668 return v2_delete_dquot(dquot);
669 return 0;
672 static struct quota_format_ops v2_format_ops = {
673 .check_quota_file = v2_check_quota_file,
674 .read_file_info = v2_read_file_info,
675 .write_file_info = v2_write_file_info,
676 .free_file_info = NULL,
677 .read_dqblk = v2_read_dquot,
678 .commit_dqblk = v2_write_dquot,
679 .release_dqblk = v2_release_dquot,
682 static struct quota_format_type v2_quota_format = {
683 .qf_fmt_id = QFMT_VFS_V0,
684 .qf_ops = &v2_format_ops,
685 .qf_owner = THIS_MODULE
688 static int __init init_v2_quota_format(void)
690 return register_quota_format(&v2_quota_format);
693 static void __exit exit_v2_quota_format(void)
695 unregister_quota_format(&v2_quota_format);
698 module_init(init_v2_quota_format);
699 module_exit(exit_v2_quota_format);