Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / fs / quota_v2.c
blobc519a583e681471c86687134c764262df138caf9
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 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
63 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
64 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
65 info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
66 info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
67 info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
68 return 0;
71 /* Write information header to quota file */
72 static int v2_write_file_info(struct super_block *sb, int type)
74 struct v2_disk_dqinfo dinfo;
75 struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
76 ssize_t size;
78 spin_lock(&dq_data_lock);
79 info->dqi_flags &= ~DQF_INFO_DIRTY;
80 dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
81 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
82 dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
83 spin_unlock(&dq_data_lock);
84 dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
85 dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
86 dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
87 size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
88 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
89 if (size != sizeof(struct v2_disk_dqinfo)) {
90 printk(KERN_WARNING "Can't write info structure on device %s.\n",
91 sb->s_id);
92 return -1;
94 return 0;
97 static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
99 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
100 m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
101 m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
102 m->dqb_itime = le64_to_cpu(d->dqb_itime);
103 m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
104 m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
105 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
106 m->dqb_btime = le64_to_cpu(d->dqb_btime);
109 static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
111 d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
112 d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
113 d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
114 d->dqb_itime = cpu_to_le64(m->dqb_itime);
115 d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
116 d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
117 d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
118 d->dqb_btime = cpu_to_le64(m->dqb_btime);
119 d->dqb_id = cpu_to_le32(id);
122 static dqbuf_t getdqbuf(void)
124 dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_NOFS);
125 if (!buf)
126 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
127 return buf;
130 static inline void freedqbuf(dqbuf_t buf)
132 kfree(buf);
135 static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
137 memset(buf, 0, V2_DQBLKSIZE);
138 return sb->s_op->quota_read(sb, type, (char *)buf,
139 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
142 static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
144 return sb->s_op->quota_write(sb, type, (char *)buf,
145 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
148 /* Remove empty block from list and return it */
149 static int get_free_dqblk(struct super_block *sb, int type)
151 dqbuf_t buf = getdqbuf();
152 struct mem_dqinfo *info = sb_dqinfo(sb, type);
153 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
154 int ret, blk;
156 if (!buf)
157 return -ENOMEM;
158 if (info->u.v2_i.dqi_free_blk) {
159 blk = info->u.v2_i.dqi_free_blk;
160 if ((ret = read_blk(sb, type, blk, buf)) < 0)
161 goto out_buf;
162 info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
164 else {
165 memset(buf, 0, V2_DQBLKSIZE);
166 /* Assure block allocation... */
167 if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0)
168 goto out_buf;
169 blk = info->u.v2_i.dqi_blocks++;
171 mark_info_dirty(sb, type);
172 ret = blk;
173 out_buf:
174 freedqbuf(buf);
175 return ret;
178 /* Insert empty block to the list */
179 static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
181 struct mem_dqinfo *info = sb_dqinfo(sb, type);
182 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
183 int err;
185 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk);
186 dh->dqdh_prev_free = cpu_to_le32(0);
187 dh->dqdh_entries = cpu_to_le16(0);
188 info->u.v2_i.dqi_free_blk = blk;
189 mark_info_dirty(sb, type);
190 /* Some strange block. We had better leave it... */
191 if ((err = write_blk(sb, type, blk, buf)) < 0)
192 return err;
193 return 0;
196 /* Remove given block from the list of blocks with free entries */
197 static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
199 dqbuf_t tmpbuf = getdqbuf();
200 struct mem_dqinfo *info = sb_dqinfo(sb, type);
201 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
202 uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
203 int err;
205 if (!tmpbuf)
206 return -ENOMEM;
207 if (nextblk) {
208 if ((err = read_blk(sb, type, nextblk, tmpbuf)) < 0)
209 goto out_buf;
210 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
211 if ((err = write_blk(sb, type, nextblk, tmpbuf)) < 0)
212 goto out_buf;
214 if (prevblk) {
215 if ((err = read_blk(sb, type, prevblk, tmpbuf)) < 0)
216 goto out_buf;
217 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
218 if ((err = write_blk(sb, type, prevblk, tmpbuf)) < 0)
219 goto out_buf;
221 else {
222 info->u.v2_i.dqi_free_entry = nextblk;
223 mark_info_dirty(sb, type);
225 freedqbuf(tmpbuf);
226 dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
227 /* No matter whether write succeeds block is out of list */
228 if (write_blk(sb, type, blk, buf) < 0)
229 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
230 return 0;
231 out_buf:
232 freedqbuf(tmpbuf);
233 return err;
236 /* Insert given block to the beginning of list with free entries */
237 static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
239 dqbuf_t tmpbuf = getdqbuf();
240 struct mem_dqinfo *info = sb_dqinfo(sb, type);
241 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
242 int err;
244 if (!tmpbuf)
245 return -ENOMEM;
246 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
247 dh->dqdh_prev_free = cpu_to_le32(0);
248 if ((err = write_blk(sb, type, blk, buf)) < 0)
249 goto out_buf;
250 if (info->u.v2_i.dqi_free_entry) {
251 if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
252 goto out_buf;
253 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
254 if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
255 goto out_buf;
257 freedqbuf(tmpbuf);
258 info->u.v2_i.dqi_free_entry = blk;
259 mark_info_dirty(sb, type);
260 return 0;
261 out_buf:
262 freedqbuf(tmpbuf);
263 return err;
266 /* Find space for dquot */
267 static uint find_free_dqentry(struct dquot *dquot, int *err)
269 struct super_block *sb = dquot->dq_sb;
270 struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
271 uint blk, i;
272 struct v2_disk_dqdbheader *dh;
273 struct v2_disk_dqblk *ddquot;
274 struct v2_disk_dqblk fakedquot;
275 dqbuf_t buf;
277 *err = 0;
278 if (!(buf = getdqbuf())) {
279 *err = -ENOMEM;
280 return 0;
282 dh = (struct v2_disk_dqdbheader *)buf;
283 ddquot = GETENTRIES(buf);
284 if (info->u.v2_i.dqi_free_entry) {
285 blk = info->u.v2_i.dqi_free_entry;
286 if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0)
287 goto out_buf;
289 else {
290 blk = get_free_dqblk(sb, dquot->dq_type);
291 if ((int)blk < 0) {
292 *err = blk;
293 freedqbuf(buf);
294 return 0;
296 memset(buf, 0, V2_DQBLKSIZE);
297 /* This is enough as block is already zeroed and entry list is empty... */
298 info->u.v2_i.dqi_free_entry = blk;
299 mark_info_dirty(sb, dquot->dq_type);
301 if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */
302 if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
303 printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
304 goto out_buf;
306 dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
307 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
308 /* Find free structure in block */
309 for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
310 #ifdef __QUOTA_V2_PARANOIA
311 if (i == V2_DQSTRINBLK) {
312 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
313 *err = -EIO;
314 goto out_buf;
316 #endif
317 if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) {
318 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
319 goto out_buf;
321 dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
322 freedqbuf(buf);
323 return blk;
324 out_buf:
325 freedqbuf(buf);
326 return 0;
329 /* Insert reference to structure into the trie */
330 static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
332 struct super_block *sb = dquot->dq_sb;
333 dqbuf_t buf;
334 int ret = 0, newson = 0, newact = 0;
335 __le32 *ref;
336 uint newblk;
338 if (!(buf = getdqbuf()))
339 return -ENOMEM;
340 if (!*treeblk) {
341 ret = get_free_dqblk(sb, dquot->dq_type);
342 if (ret < 0)
343 goto out_buf;
344 *treeblk = ret;
345 memset(buf, 0, V2_DQBLKSIZE);
346 newact = 1;
348 else {
349 if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) {
350 printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
351 goto out_buf;
354 ref = (__le32 *)buf;
355 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
356 if (!newblk)
357 newson = 1;
358 if (depth == V2_DQTREEDEPTH-1) {
359 #ifdef __QUOTA_V2_PARANOIA
360 if (newblk) {
361 printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]));
362 ret = -EIO;
363 goto out_buf;
365 #endif
366 newblk = find_free_dqentry(dquot, &ret);
368 else
369 ret = do_insert_tree(dquot, &newblk, depth+1);
370 if (newson && ret >= 0) {
371 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
372 ret = write_blk(sb, dquot->dq_type, *treeblk, buf);
374 else if (newact && ret < 0)
375 put_free_dqblk(sb, dquot->dq_type, buf, *treeblk);
376 out_buf:
377 freedqbuf(buf);
378 return ret;
381 /* Wrapper for inserting quota structure into tree */
382 static inline int dq_insert_tree(struct dquot *dquot)
384 int tmp = V2_DQTREEOFF;
385 return do_insert_tree(dquot, &tmp, 0);
389 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
391 static int v2_write_dquot(struct dquot *dquot)
393 int type = dquot->dq_type;
394 ssize_t ret;
395 struct v2_disk_dqblk ddquot, empty;
397 /* dq_off is guarded by dqio_mutex */
398 if (!dquot->dq_off)
399 if ((ret = dq_insert_tree(dquot)) < 0) {
400 printk(KERN_ERR "VFS: Error %zd occurred while creating quota.\n", ret);
401 return ret;
403 spin_lock(&dq_data_lock);
404 mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
405 /* Argh... We may need to write structure full of zeroes but that would be
406 * treated as an empty place by the rest of the code. Format change would
407 * be definitely cleaner but the problems probably are not worth it */
408 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
409 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
410 ddquot.dqb_itime = cpu_to_le64(1);
411 spin_unlock(&dq_data_lock);
412 ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
413 (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
414 if (ret != sizeof(struct v2_disk_dqblk)) {
415 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
416 if (ret >= 0)
417 ret = -ENOSPC;
419 else
420 ret = 0;
421 dqstats.writes++;
423 return ret;
426 /* Free dquot entry in data block */
427 static int free_dqentry(struct dquot *dquot, uint blk)
429 struct super_block *sb = dquot->dq_sb;
430 int type = dquot->dq_type;
431 struct v2_disk_dqdbheader *dh;
432 dqbuf_t buf = getdqbuf();
433 int ret = 0;
435 if (!buf)
436 return -ENOMEM;
437 if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
438 printk(KERN_ERR "VFS: Quota structure has offset to other "
439 "block (%u) than it should (%u).\n", blk,
440 (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
441 goto out_buf;
443 if ((ret = read_blk(sb, type, blk, buf)) < 0) {
444 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
445 goto out_buf;
447 dh = (struct v2_disk_dqdbheader *)buf;
448 dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
449 if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
450 if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||
451 (ret = put_free_dqblk(sb, type, buf, blk)) < 0) {
452 printk(KERN_ERR "VFS: Can't move quota data block (%u) "
453 "to free list.\n", blk);
454 goto out_buf;
457 else {
458 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
459 sizeof(struct v2_disk_dqblk));
460 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
461 /* Insert will write block itself */
462 if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
463 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
464 goto out_buf;
467 else
468 if ((ret = write_blk(sb, type, blk, buf)) < 0) {
469 printk(KERN_ERR "VFS: Can't write quota data "
470 "block %u\n", blk);
471 goto out_buf;
474 dquot->dq_off = 0; /* Quota is now unattached */
475 out_buf:
476 freedqbuf(buf);
477 return ret;
480 /* Remove reference to dquot from tree */
481 static int remove_tree(struct dquot *dquot, uint *blk, int depth)
483 struct super_block *sb = dquot->dq_sb;
484 int type = dquot->dq_type;
485 dqbuf_t buf = getdqbuf();
486 int ret = 0;
487 uint newblk;
488 __le32 *ref = (__le32 *)buf;
490 if (!buf)
491 return -ENOMEM;
492 if ((ret = read_blk(sb, type, *blk, buf)) < 0) {
493 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
494 goto out_buf;
496 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
497 if (depth == V2_DQTREEDEPTH-1) {
498 ret = free_dqentry(dquot, newblk);
499 newblk = 0;
501 else
502 ret = remove_tree(dquot, &newblk, depth+1);
503 if (ret >= 0 && !newblk) {
504 int i;
505 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
506 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */
507 /* Don't put the root block into the free block list */
508 if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) {
509 put_free_dqblk(sb, type, buf, *blk);
510 *blk = 0;
512 else
513 if ((ret = write_blk(sb, type, *blk, buf)) < 0)
514 printk(KERN_ERR "VFS: Can't write quota tree "
515 "block %u.\n", *blk);
517 out_buf:
518 freedqbuf(buf);
519 return ret;
522 /* Delete dquot from tree */
523 static int v2_delete_dquot(struct dquot *dquot)
525 uint tmp = V2_DQTREEOFF;
527 if (!dquot->dq_off) /* Even not allocated? */
528 return 0;
529 return remove_tree(dquot, &tmp, 0);
532 /* Find entry in block */
533 static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
535 dqbuf_t buf = getdqbuf();
536 loff_t ret = 0;
537 int i;
538 struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
540 if (!buf)
541 return -ENOMEM;
542 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
543 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
544 goto out_buf;
546 if (dquot->dq_id)
547 for (i = 0; i < V2_DQSTRINBLK &&
548 le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
549 else { /* ID 0 as a bit more complicated searching... */
550 struct v2_disk_dqblk fakedquot;
552 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
553 for (i = 0; i < V2_DQSTRINBLK; i++)
554 if (!le32_to_cpu(ddquot[i].dqb_id) &&
555 memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
556 break;
558 if (i == V2_DQSTRINBLK) {
559 printk(KERN_ERR "VFS: Quota for id %u referenced "
560 "but not present.\n", dquot->dq_id);
561 ret = -EIO;
562 goto out_buf;
564 else
565 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
566 v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
567 out_buf:
568 freedqbuf(buf);
569 return ret;
572 /* Find entry for given id in the tree */
573 static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
575 dqbuf_t buf = getdqbuf();
576 loff_t ret = 0;
577 __le32 *ref = (__le32 *)buf;
579 if (!buf)
580 return -ENOMEM;
581 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
582 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
583 goto out_buf;
585 ret = 0;
586 blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
587 if (!blk) /* No reference? */
588 goto out_buf;
589 if (depth < V2_DQTREEDEPTH-1)
590 ret = find_tree_dqentry(dquot, blk, depth+1);
591 else
592 ret = find_block_dqentry(dquot, blk);
593 out_buf:
594 freedqbuf(buf);
595 return ret;
598 /* Find entry for given id in the tree - wrapper function */
599 static inline loff_t find_dqentry(struct dquot *dquot)
601 return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
604 static int v2_read_dquot(struct dquot *dquot)
606 int type = dquot->dq_type;
607 loff_t offset;
608 struct v2_disk_dqblk ddquot, empty;
609 int ret = 0;
611 #ifdef __QUOTA_V2_PARANOIA
612 /* Invalidated quota? */
613 if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) {
614 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
615 return -EIO;
617 #endif
618 offset = find_dqentry(dquot);
619 if (offset <= 0) { /* Entry not present? */
620 if (offset < 0)
621 printk(KERN_ERR "VFS: Can't read quota "
622 "structure for id %u.\n", dquot->dq_id);
623 dquot->dq_off = 0;
624 set_bit(DQ_FAKE_B, &dquot->dq_flags);
625 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
626 ret = offset;
628 else {
629 dquot->dq_off = offset;
630 if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
631 (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
632 != sizeof(struct v2_disk_dqblk)) {
633 if (ret >= 0)
634 ret = -EIO;
635 printk(KERN_ERR "VFS: Error while reading quota "
636 "structure for id %u.\n", dquot->dq_id);
637 memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
639 else {
640 ret = 0;
641 /* We need to escape back all-zero structure */
642 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
643 empty.dqb_itime = cpu_to_le64(1);
644 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
645 ddquot.dqb_itime = 0;
647 disk2memdqb(&dquot->dq_dqb, &ddquot);
648 if (!dquot->dq_dqb.dqb_bhardlimit &&
649 !dquot->dq_dqb.dqb_bsoftlimit &&
650 !dquot->dq_dqb.dqb_ihardlimit &&
651 !dquot->dq_dqb.dqb_isoftlimit)
652 set_bit(DQ_FAKE_B, &dquot->dq_flags);
654 dqstats.reads++;
656 return ret;
659 /* Check whether dquot should not be deleted. We know we are
660 * the only one operating on dquot (thanks to dq_lock) */
661 static int v2_release_dquot(struct dquot *dquot)
663 if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
664 return v2_delete_dquot(dquot);
665 return 0;
668 static struct quota_format_ops v2_format_ops = {
669 .check_quota_file = v2_check_quota_file,
670 .read_file_info = v2_read_file_info,
671 .write_file_info = v2_write_file_info,
672 .free_file_info = NULL,
673 .read_dqblk = v2_read_dquot,
674 .commit_dqblk = v2_write_dquot,
675 .release_dqblk = v2_release_dquot,
678 static struct quota_format_type v2_quota_format = {
679 .qf_fmt_id = QFMT_VFS_V0,
680 .qf_ops = &v2_format_ops,
681 .qf_owner = THIS_MODULE
684 static int __init init_v2_quota_format(void)
686 return register_quota_format(&v2_quota_format);
689 static void __exit exit_v2_quota_format(void)
691 unregister_quota_format(&v2_quota_format);
694 module_init(init_v2_quota_format);
695 module_exit(exit_v2_quota_format);