blob: 23b647f25d08a405bad3ba8917d550f120d60ccf [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * vfsv0 quota IO operations on file
3 */
4
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
15#include <asm/byteorder.h>
16
17MODULE_AUTHOR("Jan Kara");
18MODULE_DESCRIPTION("Quota format v2 support");
19MODULE_LICENSE("GPL");
20
21#define __QUOTA_V2_PARANOIA
22
23typedef char *dqbuf_t;
24
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)))
27
28/* Check whether given file is really vfsv0 quotafile */
29static 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;
35
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)) {
Andrew Morton8c17e1e2006-02-03 03:04:03 -080038 printk("quota_v2: failed read expected=%zd got=%zd\n",
Valdis.Kletnieks@vt.edu31358062006-01-14 13:21:10 -080039 sizeof(struct v2_disk_dqheader), size);
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 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}
47
48/* Read information header from quota file */
49static 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;
54
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 }
Andrew Perepechko338bf9a2008-04-28 02:14:31 -070062 /* limits are stored as unsigned 32-bit data */
63 info->dqi_maxblimit = 0xffffffff;
64 info->dqi_maxilimit = 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 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;
72}
73
74/* Write information header to quota file */
75static int v2_write_file_info(struct super_block *sb, int type)
76{
77 struct v2_disk_dqinfo dinfo;
78 struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
79 ssize_t size;
80
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;
96 }
97 return 0;
98}
99
100static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
101{
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);
110}
111
112static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
113{
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);
123}
124
125static dqbuf_t getdqbuf(void)
126{
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;
131}
132
133static inline void freedqbuf(dqbuf_t buf)
134{
135 kfree(buf);
136}
137
138static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
139{
140 memset(buf, 0, V2_DQBLKSIZE);
141 return sb->s_op->quota_read(sb, type, (char *)buf,
142 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
143}
144
145static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
146{
147 return sb->s_op->quota_write(sb, type, (char *)buf,
148 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
149}
150
151/* Remove empty block from list and return it */
152static int get_free_dqblk(struct super_block *sb, int type)
153{
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;
158
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);
166 }
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++;
173 }
174 mark_info_dirty(sb, type);
175 ret = blk;
176out_buf:
177 freedqbuf(buf);
178 return ret;
179}
180
181/* Insert empty block to the list */
182static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
183{
184 struct mem_dqinfo *info = sb_dqinfo(sb, type);
185 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
186 int err;
187
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;
197}
198
199/* Remove given block from the list of blocks with free entries */
200static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
201{
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;
207
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;
216 }
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;
223 }
224 else {
225 info->u.v2_i.dqi_free_entry = nextblk;
226 mark_info_dirty(sb, type);
227 }
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;
234out_buf:
235 freedqbuf(tmpbuf);
236 return err;
237}
238
239/* Insert given block to the beginning of list with free entries */
240static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
241{
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;
246
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;
259 }
260 freedqbuf(tmpbuf);
261 info->u.v2_i.dqi_free_entry = blk;
262 mark_info_dirty(sb, type);
263 return 0;
264out_buf:
265 freedqbuf(tmpbuf);
266 return err;
267}
268
269/* Find space for dquot */
270static uint find_free_dqentry(struct dquot *dquot, int *err)
271{
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;
279
280 *err = 0;
281 if (!(buf = getdqbuf())) {
282 *err = -ENOMEM;
283 return 0;
284 }
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;
291 }
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;
298 }
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);
303 }
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;
308 }
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;
318 }
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;
323 }
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;
327out_buf:
328 freedqbuf(buf);
329 return 0;
330}
331
332/* Insert reference to structure into the trie */
333static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
334{
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;
340
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;
350 }
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;
355 }
356 }
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;
367 }
368#endif
369 newblk = find_free_dqentry(dquot, &ret);
370 }
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);
376 }
377 else if (newact && ret < 0)
378 put_free_dqblk(sb, dquot->dq_type, buf, *treeblk);
379out_buf:
380 freedqbuf(buf);
381 return ret;
382}
383
384/* Wrapper for inserting quota structure into tree */
385static inline int dq_insert_tree(struct dquot *dquot)
386{
387 int tmp = V2_DQTREEOFF;
388 return do_insert_tree(dquot, &tmp, 0);
389}
390
391/*
392 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
393 */
394static int v2_write_dquot(struct dquot *dquot)
395{
396 int type = dquot->dq_type;
397 ssize_t ret;
398 struct v2_disk_dqblk ddquot, empty;
399
Ingo Molnard3be9152006-03-23 03:00:29 -0800400 /* dq_off is guarded by dqio_mutex */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 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;
405 }
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;
421 }
422 else
423 ret = 0;
424 dqstats.writes++;
425
426 return ret;
427}
428
429/* Free dquot entry in data block */
430static int free_dqentry(struct dquot *dquot, uint blk)
431{
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;
437
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;
445 }
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;
449 }
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;
458 }
459 }
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;
468 }
469 }
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;
475 }
476 }
477 dquot->dq_off = 0; /* Quota is now unattached */
478out_buf:
479 freedqbuf(buf);
480 return ret;
481}
482
483/* Remove reference to dquot from tree */
484static int remove_tree(struct dquot *dquot, uint *blk, int depth)
485{
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;
492
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;
498 }
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;
503 }
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? */
Niu YaWeie821d942005-04-16 15:25:47 -0700510 /* Don't put the root block into the free block list */
511 if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 put_free_dqblk(sb, type, buf, *blk);
513 *blk = 0;
514 }
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);
519 }
520out_buf:
521 freedqbuf(buf);
522 return ret;
523}
524
525/* Delete dquot from tree */
526static int v2_delete_dquot(struct dquot *dquot)
527{
528 uint tmp = V2_DQTREEOFF;
529
530 if (!dquot->dq_off) /* Even not allocated? */
531 return 0;
532 return remove_tree(dquot, &tmp, 0);
533}
534
535/* Find entry in block */
536static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
537{
538 dqbuf_t buf = getdqbuf();
539 loff_t ret = 0;
540 int i;
541 struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
542
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;
548 }
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;
554
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;
560 }
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;
566 }
567 else
568 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
569 v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
570out_buf:
571 freedqbuf(buf);
572 return ret;
573}
574
575/* Find entry for given id in the tree */
576static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
577{
578 dqbuf_t buf = getdqbuf();
579 loff_t ret = 0;
580 __le32 *ref = (__le32 *)buf;
581
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;
587 }
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);
596out_buf:
597 freedqbuf(buf);
598 return ret;
599}
600
601/* Find entry for given id in the tree - wrapper function */
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 loff_t offset;
611 struct v2_disk_dqblk ddquot, empty;
612 int ret = 0;
613
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;
619 }
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;
630 }
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));
641 }
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;
649 }
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);
656 }
657 dqstats.reads++;
658
659 return ret;
660}
661
662/* Check whether dquot should not be deleted. We know we are
663 * the only one operating on dquot (thanks to dq_lock) */
664static int v2_release_dquot(struct dquot *dquot)
665{
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;
669}
670
671static 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,
679};
680
681static 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
685};
686
687static int __init init_v2_quota_format(void)
688{
689 return register_quota_format(&v2_quota_format);
690}
691
692static void __exit exit_v2_quota_format(void)
693{
694 unregister_quota_format(&v2_quota_format);
695}
696
697module_init(init_v2_quota_format);
698module_exit(exit_v2_quota_format);