1
2
3
4
5#include <linux/errno.h>
6#include <linux/fs.h>
7#include <linux/dqblk_v2.h>
8#include <linux/quotaio_v2.h>
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/slab.h>
13
14#include <asm/byteorder.h>
15#include <asm/uaccess.h>
16
17#define __QUOTA_V2_PARANOIA
18
19typedef char *dqbuf_t;
20
21#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
22#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))
23
24
25static int v2_check_quota_file(struct super_block *sb, int type)
26{
27 struct v2_disk_dqheader dqhead;
28 struct file *f = sb_dqopt(sb)->files[type];
29 mm_segment_t fs;
30 ssize_t size;
31 loff_t offset = 0;
32 static const uint quota_magics[] = V2_INITQMAGICS;
33 static const uint quota_versions[] = V2_INITQVERSIONS;
34
35 fs = get_fs();
36 set_fs(KERNEL_DS);
37 size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset);
38 set_fs(fs);
39 if (size != sizeof(struct v2_disk_dqheader))
40 return 0;
41 if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
42 le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
43 return 0;
44 return 1;
45}
46
47
48static int v2_read_file_info(struct super_block *sb, int type)
49{
50 mm_segment_t fs;
51 struct v2_disk_dqinfo dinfo;
52 struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
53 struct file *f = sb_dqopt(sb)->files[type];
54 ssize_t size;
55 loff_t offset = V2_DQINFOOFF;
56
57 fs = get_fs();
58 set_fs(KERNEL_DS);
59 size = f->f_op->read(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset);
60 set_fs(fs);
61 if (size != sizeof(struct v2_disk_dqinfo)) {
62 printk(KERN_WARNING "Can't read info structure on device %s.\n",
63 f->f_vfsmnt->mnt_sb->s_id);
64 return -1;
65 }
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;
73}
74
75
76static int v2_write_file_info(struct super_block *sb, int type)
77{
78 mm_segment_t fs;
79 struct v2_disk_dqinfo dinfo;
80 struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
81 struct file *f = sb_dqopt(sb)->files[type];
82 ssize_t size;
83 loff_t offset = V2_DQINFOOFF;
84
85 info->dqi_flags &= ~DQF_INFO_DIRTY;
86 dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
87 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
88 dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
89 dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
90 dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
91 dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
92 fs = get_fs();
93 set_fs(KERNEL_DS);
94 size = f->f_op->write(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset);
95 set_fs(fs);
96 if (size != sizeof(struct v2_disk_dqinfo)) {
97 printk(KERN_WARNING "Can't write info structure on device %s.\n",
98 f->f_vfsmnt->mnt_sb->s_id);
99 return -1;
100 }
101 return 0;
102}
103
104static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
105{
106 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
107 m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
108 m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
109 m->dqb_itime = le64_to_cpu(d->dqb_itime);
110 m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
111 m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
112 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
113 m->dqb_btime = le64_to_cpu(d->dqb_btime);
114}
115
116static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
117{
118 d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
119 d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
120 d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
121 d->dqb_itime = cpu_to_le64(m->dqb_itime);
122 d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
123 d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
124 d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
125 d->dqb_btime = cpu_to_le64(m->dqb_btime);
126 d->dqb_id = cpu_to_le32(id);
127}
128
129static dqbuf_t getdqbuf(void)
130{
131 dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_KERNEL);
132 if (!buf)
133 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
134 return buf;
135}
136
137static inline void freedqbuf(dqbuf_t buf)
138{
139 kfree(buf);
140}
141
142static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
143{
144 mm_segment_t fs;
145 ssize_t ret;
146 loff_t offset = blk<<V2_DQBLKSIZE_BITS;
147
148 memset(buf, 0, V2_DQBLKSIZE);
149 fs = get_fs();
150 set_fs(KERNEL_DS);
151 ret = filp->f_op->read(filp, (char *)buf, V2_DQBLKSIZE, &offset);
152 set_fs(fs);
153 return ret;
154}
155
156static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
157{
158 mm_segment_t fs;
159 ssize_t ret;
160 loff_t offset = blk<<V2_DQBLKSIZE_BITS;
161
162 fs = get_fs();
163 set_fs(KERNEL_DS);
164 ret = filp->f_op->write(filp, (char *)buf, V2_DQBLKSIZE, &offset);
165 set_fs(fs);
166 return ret;
167
168}
169
170
171static int get_free_dqblk(struct file *filp, struct mem_dqinfo *info)
172{
173 dqbuf_t buf = getdqbuf();
174 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
175 int ret, blk;
176
177 if (!buf)
178 return -ENOMEM;
179 if (info->u.v2_i.dqi_free_blk) {
180 blk = info->u.v2_i.dqi_free_blk;
181 if ((ret = read_blk(filp, blk, buf)) < 0)
182 goto out_buf;
183 info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
184 }
185 else {
186 memset(buf, 0, V2_DQBLKSIZE);
187 if ((ret = write_blk(filp, info->u.v2_i.dqi_blocks, buf)) < 0)
188 goto out_buf;
189 blk = info->u.v2_i.dqi_blocks++;
190 }
191 mark_info_dirty(info);
192 ret = blk;
193out_buf:
194 freedqbuf(buf);
195 return ret;
196}
197
198
199static int put_free_dqblk(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
200{
201 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
202 int err;
203
204 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk);
205 dh->dqdh_prev_free = cpu_to_le32(0);
206 dh->dqdh_entries = cpu_to_le16(0);
207 info->u.v2_i.dqi_free_blk = blk;
208 mark_info_dirty(info);
209 if ((err = write_blk(filp, blk, buf)) < 0)
210 return err;
211 return 0;
212}
213
214
215static int remove_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
216{
217 dqbuf_t tmpbuf = getdqbuf();
218 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
219 uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
220 int err;
221
222 if (!tmpbuf)
223 return -ENOMEM;
224 if (nextblk) {
225 if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
226 goto out_buf;
227 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
228 if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
229 goto out_buf;
230 }
231 if (prevblk) {
232 if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
233 goto out_buf;
234 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
235 if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
236 goto out_buf;
237 }
238 else {
239 info->u.v2_i.dqi_free_entry = nextblk;
240 mark_info_dirty(info);
241 }
242 freedqbuf(tmpbuf);
243 dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
244 if (write_blk(filp, blk, buf) < 0)
245 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
246 return 0;
247out_buf:
248 freedqbuf(tmpbuf);
249 return err;
250}
251
252
253static int insert_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
254{
255 dqbuf_t tmpbuf = getdqbuf();
256 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
257 int err;
258
259 if (!tmpbuf)
260 return -ENOMEM;
261 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
262 dh->dqdh_prev_free = cpu_to_le32(0);
263 if ((err = write_blk(filp, blk, buf)) < 0)
264 goto out_buf;
265 if (info->u.v2_i.dqi_free_entry) {
266 if ((err = read_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
267 goto out_buf;
268 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
269 if ((err = write_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
270 goto out_buf;
271 }
272 freedqbuf(tmpbuf);
273 info->u.v2_i.dqi_free_entry = blk;
274 mark_info_dirty(info);
275 return 0;
276out_buf:
277 freedqbuf(tmpbuf);
278 return err;
279}
280
281
282static uint find_free_dqentry(struct dquot *dquot, int *err)
283{
284 struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
285 struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info+dquot->dq_type;
286 uint blk, i;
287 struct v2_disk_dqdbheader *dh;
288 struct v2_disk_dqblk *ddquot;
289 struct v2_disk_dqblk fakedquot;
290 dqbuf_t buf;
291
292 *err = 0;
293 if (!(buf = getdqbuf())) {
294 *err = -ENOMEM;
295 return 0;
296 }
297 dh = (struct v2_disk_dqdbheader *)buf;
298 ddquot = GETENTRIES(buf);
299 if (info->u.v2_i.dqi_free_entry) {
300 blk = info->u.v2_i.dqi_free_entry;
301 if ((*err = read_blk(filp, blk, buf)) < 0)
302 goto out_buf;
303 }
304 else {
305 blk = get_free_dqblk(filp, info);
306 if ((int)blk < 0) {
307 *err = blk;
308 return 0;
309 }
310 memset(buf, 0, V2_DQBLKSIZE);
311 info->u.v2_i.dqi_free_entry = blk;
312 mark_info_dirty(info);
313 }
314 if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK)
315 if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) {
316 printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
317 goto out_buf;
318 }
319 dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
320 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
321
322 for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
323#ifdef __QUOTA_V2_PARANOIA
324 if (i == V2_DQSTRINBLK) {
325 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
326 *err = -EIO;
327 goto out_buf;
328 }
329#endif
330 if ((*err = write_blk(filp, blk, buf)) < 0) {
331 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
332 goto out_buf;
333 }
334 dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
335 freedqbuf(buf);
336 return blk;
337out_buf:
338 freedqbuf(buf);
339 return 0;
340}
341
342
343static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
344{
345 struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
346 struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
347 dqbuf_t buf;
348 int ret = 0, newson = 0, newact = 0;
349 u32 *ref;
350 uint newblk;
351
352 if (!(buf = getdqbuf()))
353 return -ENOMEM;
354 if (!*treeblk) {
355 ret = get_free_dqblk(filp, info);
356 if (ret < 0)
357 goto out_buf;
358 *treeblk = ret;
359 memset(buf, 0, V2_DQBLKSIZE);
360 newact = 1;
361 }
362 else {
363 if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
364 printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
365 goto out_buf;
366 }
367 }
368 ref = (u32 *)buf;
369 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
370 if (!newblk)
371 newson = 1;
372 if (depth == V2_DQTREEDEPTH-1) {
373#ifdef __QUOTA_V2_PARANOIA
374 if (newblk) {
375 printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", ref[GETIDINDEX(dquot->dq_id, depth)]);
376 ret = -EIO;
377 goto out_buf;
378 }
379#endif
380 newblk = find_free_dqentry(dquot, &ret);
381 }
382 else
383 ret = do_insert_tree(dquot, &newblk, depth+1);
384 if (newson && ret >= 0) {
385 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
386 ret = write_blk(filp, *treeblk, buf);
387 }
388 else if (newact && ret < 0)
389 put_free_dqblk(filp, info, buf, *treeblk);
390out_buf:
391 freedqbuf(buf);
392 return ret;
393}
394
395
396static inline int dq_insert_tree(struct dquot *dquot)
397{
398 int tmp = V2_DQTREEOFF;
399 return do_insert_tree(dquot, &tmp, 0);
400}
401
402
403
404
405static int v2_write_dquot(struct dquot *dquot)
406{
407 int type = dquot->dq_type;
408 struct file *filp;
409 mm_segment_t fs;
410 loff_t offset;
411 ssize_t ret;
412 struct v2_disk_dqblk ddquot;
413
414 if (!dquot->dq_off)
415 if ((ret = dq_insert_tree(dquot)) < 0) {
416 printk(KERN_ERR "VFS: Error %Zd occured while creating quota.\n", ret);
417 return ret;
418 }
419 filp = sb_dqopt(dquot->dq_sb)->files[type];
420 offset = dquot->dq_off;
421 mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
422 fs = get_fs();
423 set_fs(KERNEL_DS);
424 ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset);
425 set_fs(fs);
426 if (ret != sizeof(struct v2_disk_dqblk)) {
427 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
428 if (ret >= 0)
429 ret = -ENOSPC;
430 }
431 else
432 ret = 0;
433 dqstats.writes++;
434
435 return ret;
436}
437
438
439static int free_dqentry(struct dquot *dquot, uint blk)
440{
441 struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
442 struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
443 struct v2_disk_dqdbheader *dh;
444 dqbuf_t buf = getdqbuf();
445 int ret = 0;
446
447 if (!buf)
448 return -ENOMEM;
449 if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
450 printk(KERN_ERR "VFS: Quota structure has offset to other block (%u) than it should (%u).\n", blk, (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
451 goto out_buf;
452 }
453 if ((ret = read_blk(filp, blk, buf)) < 0) {
454 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
455 goto out_buf;
456 }
457 dh = (struct v2_disk_dqdbheader *)buf;
458 dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
459 if (!le16_to_cpu(dh->dqdh_entries)) {
460 if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
461 (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
462 printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
463 goto out_buf;
464 }
465 }
466 else {
467 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk));
468 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
469
470 if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) {
471 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
472 goto out_buf;
473 }
474 }
475 else
476 if ((ret = write_blk(filp, blk, buf)) < 0) {
477 printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);
478 goto out_buf;
479 }
480 }
481 dquot->dq_off = 0;
482out_buf:
483 freedqbuf(buf);
484 return ret;
485}
486
487
488static int remove_tree(struct dquot *dquot, uint *blk, int depth)
489{
490 struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
491 struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
492 dqbuf_t buf = getdqbuf();
493 int ret = 0;
494 uint newblk;
495 u32 *ref = (u32 *)buf;
496
497 if (!buf)
498 return -ENOMEM;
499 if ((ret = read_blk(filp, *blk, buf)) < 0) {
500 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
501 goto out_buf;
502 }
503 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
504 if (depth == V2_DQTREEDEPTH-1) {
505 ret = free_dqentry(dquot, newblk);
506 newblk = 0;
507 }
508 else
509 ret = remove_tree(dquot, &newblk, depth+1);
510 if (ret >= 0 && !newblk) {
511 int i;
512 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
513 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++);
514 if (i == V2_DQBLKSIZE) {
515 put_free_dqblk(filp, info, buf, *blk);
516 *blk = 0;
517 }
518 else
519 if ((ret = write_blk(filp, *blk, buf)) < 0)
520 printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);
521 }
522out_buf:
523 freedqbuf(buf);
524 return ret;
525}
526
527
528static int v2_delete_dquot(struct dquot *dquot)
529{
530 uint tmp = V2_DQTREEOFF;
531
532 if (!dquot->dq_off)
533 return 0;
534 return remove_tree(dquot, &tmp, 0);
535}
536
537
538static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
539{
540 struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
541 dqbuf_t buf = getdqbuf();
542 loff_t ret = 0;
543 int i;
544 struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
545
546 if (!buf)
547 return -ENOMEM;
548 if ((ret = read_blk(filp, blk, buf)) < 0) {
549 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
550 goto out_buf;
551 }
552 if (dquot->dq_id)
553 for (i = 0; i < V2_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
554 else {
555 struct v2_disk_dqblk fakedquot;
556
557 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
558 for (i = 0; i < V2_DQSTRINBLK; i++)
559 if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
560 break;
561 }
562 if (i == V2_DQSTRINBLK) {
563 printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id);
564 ret = -EIO;
565 goto out_buf;
566 }
567 else
568 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
569out_buf:
570 freedqbuf(buf);
571 return ret;
572}
573
574
575static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
576{
577 struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
578 dqbuf_t buf = getdqbuf();
579 loff_t ret = 0;
580 u32 *ref = (u32 *)buf;
581
582 if (!buf)
583 return -ENOMEM;
584 if ((ret = read_blk(filp, blk, buf)) < 0) {
585 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
586 goto out_buf;
587 }
588 ret = 0;
589 blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
590 if (!blk)
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);
596out_buf:
597 freedqbuf(buf);
598 return ret;
599}
600
601
602static inline loff_t find_dqentry(struct dquot *dquot)
603{
604 return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
605}
606
607static int v2_read_dquot(struct dquot *dquot)
608{
609 int type = dquot->dq_type;
610 struct file *filp;
611 mm_segment_t fs;
612 loff_t offset;
613 struct v2_disk_dqblk ddquot;
614 int ret = 0;
615
616 filp = sb_dqopt(dquot->dq_sb)->files[type];
617
618#ifdef __QUOTA_V2_PARANOIA
619 if (!filp || !dquot->dq_sb) {
620 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
621 return -EIO;
622 }
623#endif
624 offset = find_dqentry(dquot);
625 if (offset <= 0) {
626 if (offset < 0)
627 printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
628 dquot->dq_off = 0;
629 dquot->dq_flags |= DQ_FAKE;
630 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
631 ret = offset;
632 }
633 else {
634 dquot->dq_off = offset;
635 fs = get_fs();
636 set_fs(KERNEL_DS);
637 if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset)) != sizeof(struct v2_disk_dqblk)) {
638 if (ret >= 0)
639 ret = -EIO;
640 printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id);
641 memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
642 }
643 else
644 ret = 0;
645 set_fs(fs);
646 disk2memdqb(&dquot->dq_dqb, &ddquot);
647 }
648 dqstats.reads++;
649
650 return ret;
651}
652
653
654static int v2_commit_dquot(struct dquot *dquot)
655{
656
657 dquot->dq_flags &= ~DQ_MOD;
658 if (dquot->dq_flags & DQ_FAKE && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
659 return v2_delete_dquot(dquot);
660 else
661 return v2_write_dquot(dquot);
662}
663
664static struct quota_format_ops v2_format_ops = {
665 .check_quota_file = v2_check_quota_file,
666 .read_file_info = v2_read_file_info,
667 .write_file_info = v2_write_file_info,
668 .free_file_info = NULL,
669 .read_dqblk = v2_read_dquot,
670 .commit_dqblk = v2_commit_dquot,
671};
672
673static struct quota_format_type v2_quota_format = {
674 .qf_fmt_id = QFMT_VFS_V0,
675 .qf_ops = &v2_format_ops,
676 .qf_owner = THIS_MODULE
677};
678
679static int __init init_v2_quota_format(void)
680{
681 return register_quota_format(&v2_quota_format);
682}
683
684static void __exit exit_v2_quota_format(void)
685{
686 unregister_quota_format(&v2_quota_format);
687}
688
689EXPORT_NO_SYMBOLS;
690
691module_init(init_v2_quota_format);
692module_exit(exit_v2_quota_format);
693