ia64/linux-2.6.18-xen.hg

view fs/quota_v2.c @ 524:7f8b544237bf

netfront: Allow netfront in domain 0.

This is useful if your physical network device is in a utility domain.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Apr 15 15:18:58 2008 +0100 (2008-04-15)
parents 831230e53067
children
line source
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)
30 {
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;
41 }
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;
46 }
48 /* Read information header from quota file */
49 static int v2_read_file_info(struct super_block *sb, int type)
50 {
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;
61 }
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;
69 }
71 /* Write information header to quota file */
72 static int v2_write_file_info(struct super_block *sb, int type)
73 {
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;
93 }
94 return 0;
95 }
97 static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
98 {
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);
107 }
109 static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
110 {
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);
120 }
122 static dqbuf_t getdqbuf(void)
123 {
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;
128 }
130 static inline void freedqbuf(dqbuf_t buf)
131 {
132 kfree(buf);
133 }
135 static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
136 {
137 memset(buf, 0, V2_DQBLKSIZE);
138 return sb->s_op->quota_read(sb, type, (char *)buf,
139 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
140 }
142 static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
143 {
144 return sb->s_op->quota_write(sb, type, (char *)buf,
145 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
146 }
148 /* Remove empty block from list and return it */
149 static int get_free_dqblk(struct super_block *sb, int type)
150 {
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);
163 }
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++;
170 }
171 mark_info_dirty(sb, type);
172 ret = blk;
173 out_buf:
174 freedqbuf(buf);
175 return ret;
176 }
178 /* Insert empty block to the list */
179 static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
180 {
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;
194 }
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)
198 {
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;
213 }
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;
220 }
221 else {
222 info->u.v2_i.dqi_free_entry = nextblk;
223 mark_info_dirty(sb, type);
224 }
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;
234 }
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)
238 {
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;
256 }
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;
264 }
266 /* Find space for dquot */
267 static uint find_free_dqentry(struct dquot *dquot, int *err)
268 {
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;
281 }
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;
288 }
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;
295 }
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);
300 }
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;
305 }
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;
315 }
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;
320 }
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;
327 }
329 /* Insert reference to structure into the trie */
330 static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
331 {
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;
347 }
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;
352 }
353 }
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;
364 }
365 #endif
366 newblk = find_free_dqentry(dquot, &ret);
367 }
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);
373 }
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;
379 }
381 /* Wrapper for inserting quota structure into tree */
382 static inline int dq_insert_tree(struct dquot *dquot)
383 {
384 int tmp = V2_DQTREEOFF;
385 return do_insert_tree(dquot, &tmp, 0);
386 }
388 /*
389 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
390 */
391 static int v2_write_dquot(struct dquot *dquot)
392 {
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;
402 }
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;
418 }
419 else
420 ret = 0;
421 dqstats.writes++;
423 return ret;
424 }
426 /* Free dquot entry in data block */
427 static int free_dqentry(struct dquot *dquot, uint blk)
428 {
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;
442 }
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;
446 }
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;
455 }
456 }
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;
465 }
466 }
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;
472 }
473 }
474 dquot->dq_off = 0; /* Quota is now unattached */
475 out_buf:
476 freedqbuf(buf);
477 return ret;
478 }
480 /* Remove reference to dquot from tree */
481 static int remove_tree(struct dquot *dquot, uint *blk, int depth)
482 {
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;
495 }
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;
500 }
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;
511 }
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);
516 }
517 out_buf:
518 freedqbuf(buf);
519 return ret;
520 }
522 /* Delete dquot from tree */
523 static int v2_delete_dquot(struct dquot *dquot)
524 {
525 uint tmp = V2_DQTREEOFF;
527 if (!dquot->dq_off) /* Even not allocated? */
528 return 0;
529 return remove_tree(dquot, &tmp, 0);
530 }
532 /* Find entry in block */
533 static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
534 {
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;
545 }
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;
557 }
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;
563 }
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;
570 }
572 /* Find entry for given id in the tree */
573 static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
574 {
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;
584 }
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;
596 }
598 /* Find entry for given id in the tree - wrapper function */
599 static inline loff_t find_dqentry(struct dquot *dquot)
600 {
601 return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
602 }
604 static int v2_read_dquot(struct dquot *dquot)
605 {
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;
616 }
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;
627 }
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));
638 }
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;
646 }
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);
653 }
654 dqstats.reads++;
656 return ret;
657 }
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)
662 {
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;
666 }
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,
676 };
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
682 };
684 static int __init init_v2_quota_format(void)
685 {
686 return register_quota_format(&v2_quota_format);
687 }
689 static void __exit exit_v2_quota_format(void)
690 {
691 unregister_quota_format(&v2_quota_format);
692 }
694 module_init(init_v2_quota_format);
695 module_exit(exit_v2_quota_format);