blob: 51c4717f7c6a7ade5b72d1c6717c331365dac35d [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>
Jan Kara74abb982008-07-25 01:46:51 -070014#include <linux/quotaops.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015
16#include <asm/byteorder.h>
17
18MODULE_AUTHOR("Jan Kara");
19MODULE_DESCRIPTION("Quota format v2 support");
20MODULE_LICENSE("GPL");
21
22#define __QUOTA_V2_PARANOIA
23
24typedef char *dqbuf_t;
25
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)))
28
Jan Kara12095462008-08-20 14:45:12 +020029#define QUOTABLOCK_BITS 10
30#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
31
32static inline qsize_t v2_stoqb(qsize_t space)
33{
34 return (space + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS;
35}
36
37static inline qsize_t v2_qbtos(qsize_t blocks)
38{
39 return blocks << QUOTABLOCK_BITS;
40}
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042/* Check whether given file is really vfsv0 quotafile */
43static int v2_check_quota_file(struct super_block *sb, int type)
44{
45 struct v2_disk_dqheader dqhead;
46 ssize_t size;
47 static const uint quota_magics[] = V2_INITQMAGICS;
48 static const uint quota_versions[] = V2_INITQVERSIONS;
49
50 size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
51 if (size != sizeof(struct v2_disk_dqheader)) {
Andrew Morton8c17e1e2006-02-03 03:04:03 -080052 printk("quota_v2: failed read expected=%zd got=%zd\n",
Valdis.Kletnieks@vt.edu31358062006-01-14 13:21:10 -080053 sizeof(struct v2_disk_dqheader), size);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 return 0;
55 }
56 if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
57 le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
58 return 0;
59 return 1;
60}
61
62/* Read information header from quota file */
63static int v2_read_file_info(struct super_block *sb, int type)
64{
65 struct v2_disk_dqinfo dinfo;
66 struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
67 ssize_t size;
68
69 size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
70 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
71 if (size != sizeof(struct v2_disk_dqinfo)) {
72 printk(KERN_WARNING "Can't read info structure on device %s.\n",
73 sb->s_id);
74 return -1;
75 }
Andrew Perepechko338bf9a2008-04-28 02:14:31 -070076 /* limits are stored as unsigned 32-bit data */
77 info->dqi_maxblimit = 0xffffffff;
78 info->dqi_maxilimit = 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
80 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
81 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
82 info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
83 info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
84 info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
85 return 0;
86}
87
88/* Write information header to quota file */
89static int v2_write_file_info(struct super_block *sb, int type)
90{
91 struct v2_disk_dqinfo dinfo;
92 struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
93 ssize_t size;
94
95 spin_lock(&dq_data_lock);
96 info->dqi_flags &= ~DQF_INFO_DIRTY;
97 dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
98 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
99 dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
100 spin_unlock(&dq_data_lock);
101 dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
102 dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
103 dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
104 size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
105 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
106 if (size != sizeof(struct v2_disk_dqinfo)) {
107 printk(KERN_WARNING "Can't write info structure on device %s.\n",
108 sb->s_id);
109 return -1;
110 }
111 return 0;
112}
113
114static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
115{
116 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
117 m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
118 m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
119 m->dqb_itime = le64_to_cpu(d->dqb_itime);
Jan Kara12095462008-08-20 14:45:12 +0200120 m->dqb_bhardlimit = v2_qbtos(le32_to_cpu(d->dqb_bhardlimit));
121 m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
123 m->dqb_btime = le64_to_cpu(d->dqb_btime);
124}
125
126static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
127{
128 d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
129 d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
130 d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
131 d->dqb_itime = cpu_to_le64(m->dqb_itime);
Jan Kara12095462008-08-20 14:45:12 +0200132 d->dqb_bhardlimit = cpu_to_le32(v2_qbtos(m->dqb_bhardlimit));
133 d->dqb_bsoftlimit = cpu_to_le32(v2_qbtos(m->dqb_bsoftlimit));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
135 d->dqb_btime = cpu_to_le64(m->dqb_btime);
136 d->dqb_id = cpu_to_le32(id);
137}
138
139static dqbuf_t getdqbuf(void)
140{
141 dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_NOFS);
142 if (!buf)
143 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
144 return buf;
145}
146
147static inline void freedqbuf(dqbuf_t buf)
148{
149 kfree(buf);
150}
151
152static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
153{
154 memset(buf, 0, V2_DQBLKSIZE);
155 return sb->s_op->quota_read(sb, type, (char *)buf,
156 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
157}
158
159static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
160{
161 return sb->s_op->quota_write(sb, type, (char *)buf,
162 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
163}
164
165/* Remove empty block from list and return it */
166static int get_free_dqblk(struct super_block *sb, int type)
167{
168 dqbuf_t buf = getdqbuf();
169 struct mem_dqinfo *info = sb_dqinfo(sb, type);
170 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
171 int ret, blk;
172
173 if (!buf)
174 return -ENOMEM;
175 if (info->u.v2_i.dqi_free_blk) {
176 blk = info->u.v2_i.dqi_free_blk;
177 if ((ret = read_blk(sb, type, blk, buf)) < 0)
178 goto out_buf;
179 info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
180 }
181 else {
182 memset(buf, 0, V2_DQBLKSIZE);
183 /* Assure block allocation... */
184 if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0)
185 goto out_buf;
186 blk = info->u.v2_i.dqi_blocks++;
187 }
188 mark_info_dirty(sb, type);
189 ret = blk;
190out_buf:
191 freedqbuf(buf);
192 return ret;
193}
194
195/* Insert empty block to the list */
196static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
197{
198 struct mem_dqinfo *info = sb_dqinfo(sb, type);
199 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
200 int err;
201
202 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk);
203 dh->dqdh_prev_free = cpu_to_le32(0);
204 dh->dqdh_entries = cpu_to_le16(0);
205 info->u.v2_i.dqi_free_blk = blk;
206 mark_info_dirty(sb, type);
207 /* Some strange block. We had better leave it... */
208 if ((err = write_blk(sb, type, blk, buf)) < 0)
209 return err;
210 return 0;
211}
212
213/* Remove given block from the list of blocks with free entries */
214static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
215{
216 dqbuf_t tmpbuf = getdqbuf();
217 struct mem_dqinfo *info = sb_dqinfo(sb, type);
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(sb, type, 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(sb, type, nextblk, tmpbuf)) < 0)
229 goto out_buf;
230 }
231 if (prevblk) {
232 if ((err = read_blk(sb, type, 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(sb, type, prevblk, tmpbuf)) < 0)
236 goto out_buf;
237 }
238 else {
239 info->u.v2_i.dqi_free_entry = nextblk;
240 mark_info_dirty(sb, type);
241 }
242 freedqbuf(tmpbuf);
243 dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
244 /* No matter whether write succeeds block is out of list */
245 if (write_blk(sb, type, blk, buf) < 0)
246 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
247 return 0;
248out_buf:
249 freedqbuf(tmpbuf);
250 return err;
251}
252
253/* Insert given block to the beginning of list with free entries */
254static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
255{
256 dqbuf_t tmpbuf = getdqbuf();
257 struct mem_dqinfo *info = sb_dqinfo(sb, type);
258 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
259 int err;
260
261 if (!tmpbuf)
262 return -ENOMEM;
263 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
264 dh->dqdh_prev_free = cpu_to_le32(0);
265 if ((err = write_blk(sb, type, blk, buf)) < 0)
266 goto out_buf;
267 if (info->u.v2_i.dqi_free_entry) {
268 if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
269 goto out_buf;
270 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
271 if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
272 goto out_buf;
273 }
274 freedqbuf(tmpbuf);
275 info->u.v2_i.dqi_free_entry = blk;
276 mark_info_dirty(sb, type);
277 return 0;
278out_buf:
279 freedqbuf(tmpbuf);
280 return err;
281}
282
283/* Find space for dquot */
284static uint find_free_dqentry(struct dquot *dquot, int *err)
285{
286 struct super_block *sb = dquot->dq_sb;
287 struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
288 uint blk, i;
289 struct v2_disk_dqdbheader *dh;
290 struct v2_disk_dqblk *ddquot;
291 struct v2_disk_dqblk fakedquot;
292 dqbuf_t buf;
293
294 *err = 0;
295 if (!(buf = getdqbuf())) {
296 *err = -ENOMEM;
297 return 0;
298 }
299 dh = (struct v2_disk_dqdbheader *)buf;
300 ddquot = GETENTRIES(buf);
301 if (info->u.v2_i.dqi_free_entry) {
302 blk = info->u.v2_i.dqi_free_entry;
303 if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0)
304 goto out_buf;
305 }
306 else {
307 blk = get_free_dqblk(sb, dquot->dq_type);
308 if ((int)blk < 0) {
309 *err = blk;
310 freedqbuf(buf);
311 return 0;
312 }
313 memset(buf, 0, V2_DQBLKSIZE);
314 /* This is enough as block is already zeroed and entry list is empty... */
315 info->u.v2_i.dqi_free_entry = blk;
316 mark_info_dirty(sb, dquot->dq_type);
317 }
318 if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */
319 if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
320 printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
321 goto out_buf;
322 }
Marcin Slusarze3592b12008-04-30 00:54:48 -0700323 le16_add_cpu(&dh->dqdh_entries, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
325 /* Find free structure in block */
326 for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
327#ifdef __QUOTA_V2_PARANOIA
328 if (i == V2_DQSTRINBLK) {
329 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
330 *err = -EIO;
331 goto out_buf;
332 }
333#endif
334 if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) {
335 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
336 goto out_buf;
337 }
338 dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
339 freedqbuf(buf);
340 return blk;
341out_buf:
342 freedqbuf(buf);
343 return 0;
344}
345
346/* Insert reference to structure into the trie */
347static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
348{
349 struct super_block *sb = dquot->dq_sb;
350 dqbuf_t buf;
351 int ret = 0, newson = 0, newact = 0;
352 __le32 *ref;
353 uint newblk;
354
355 if (!(buf = getdqbuf()))
356 return -ENOMEM;
357 if (!*treeblk) {
358 ret = get_free_dqblk(sb, dquot->dq_type);
359 if (ret < 0)
360 goto out_buf;
361 *treeblk = ret;
362 memset(buf, 0, V2_DQBLKSIZE);
363 newact = 1;
364 }
365 else {
366 if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) {
367 printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
368 goto out_buf;
369 }
370 }
371 ref = (__le32 *)buf;
372 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
373 if (!newblk)
374 newson = 1;
375 if (depth == V2_DQTREEDEPTH-1) {
376#ifdef __QUOTA_V2_PARANOIA
377 if (newblk) {
378 printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]));
379 ret = -EIO;
380 goto out_buf;
381 }
382#endif
383 newblk = find_free_dqentry(dquot, &ret);
384 }
385 else
386 ret = do_insert_tree(dquot, &newblk, depth+1);
387 if (newson && ret >= 0) {
388 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
389 ret = write_blk(sb, dquot->dq_type, *treeblk, buf);
390 }
391 else if (newact && ret < 0)
392 put_free_dqblk(sb, dquot->dq_type, buf, *treeblk);
393out_buf:
394 freedqbuf(buf);
395 return ret;
396}
397
398/* Wrapper for inserting quota structure into tree */
399static inline int dq_insert_tree(struct dquot *dquot)
400{
401 int tmp = V2_DQTREEOFF;
402 return do_insert_tree(dquot, &tmp, 0);
403}
404
405/*
406 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
407 */
408static int v2_write_dquot(struct dquot *dquot)
409{
410 int type = dquot->dq_type;
411 ssize_t ret;
412 struct v2_disk_dqblk ddquot, empty;
413
Ingo Molnard3be9152006-03-23 03:00:29 -0800414 /* dq_off is guarded by dqio_mutex */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 if (!dquot->dq_off)
416 if ((ret = dq_insert_tree(dquot)) < 0) {
417 printk(KERN_ERR "VFS: Error %zd occurred while creating quota.\n", ret);
418 return ret;
419 }
420 spin_lock(&dq_data_lock);
421 mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
422 /* Argh... We may need to write structure full of zeroes but that would be
423 * treated as an empty place by the rest of the code. Format change would
424 * be definitely cleaner but the problems probably are not worth it */
425 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
426 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
427 ddquot.dqb_itime = cpu_to_le64(1);
428 spin_unlock(&dq_data_lock);
429 ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
430 (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
431 if (ret != sizeof(struct v2_disk_dqblk)) {
432 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
433 if (ret >= 0)
434 ret = -ENOSPC;
435 }
436 else
437 ret = 0;
438 dqstats.writes++;
439
440 return ret;
441}
442
443/* Free dquot entry in data block */
444static int free_dqentry(struct dquot *dquot, uint blk)
445{
446 struct super_block *sb = dquot->dq_sb;
447 int type = dquot->dq_type;
448 struct v2_disk_dqdbheader *dh;
449 dqbuf_t buf = getdqbuf();
450 int ret = 0;
451
452 if (!buf)
453 return -ENOMEM;
454 if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
455 printk(KERN_ERR "VFS: Quota structure has offset to other "
456 "block (%u) than it should (%u).\n", blk,
457 (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
458 goto out_buf;
459 }
460 if ((ret = read_blk(sb, type, blk, buf)) < 0) {
461 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
462 goto out_buf;
463 }
464 dh = (struct v2_disk_dqdbheader *)buf;
Marcin Slusarze3592b12008-04-30 00:54:48 -0700465 le16_add_cpu(&dh->dqdh_entries, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
467 if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||
468 (ret = put_free_dqblk(sb, type, buf, blk)) < 0) {
469 printk(KERN_ERR "VFS: Can't move quota data block (%u) "
470 "to free list.\n", blk);
471 goto out_buf;
472 }
473 }
474 else {
475 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
476 sizeof(struct v2_disk_dqblk));
477 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
478 /* Insert will write block itself */
479 if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
480 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
481 goto out_buf;
482 }
483 }
484 else
485 if ((ret = write_blk(sb, type, blk, buf)) < 0) {
486 printk(KERN_ERR "VFS: Can't write quota data "
487 "block %u\n", blk);
488 goto out_buf;
489 }
490 }
491 dquot->dq_off = 0; /* Quota is now unattached */
492out_buf:
493 freedqbuf(buf);
494 return ret;
495}
496
497/* Remove reference to dquot from tree */
498static int remove_tree(struct dquot *dquot, uint *blk, int depth)
499{
500 struct super_block *sb = dquot->dq_sb;
501 int type = dquot->dq_type;
502 dqbuf_t buf = getdqbuf();
503 int ret = 0;
504 uint newblk;
505 __le32 *ref = (__le32 *)buf;
506
507 if (!buf)
508 return -ENOMEM;
509 if ((ret = read_blk(sb, type, *blk, buf)) < 0) {
510 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
511 goto out_buf;
512 }
513 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
514 if (depth == V2_DQTREEDEPTH-1) {
515 ret = free_dqentry(dquot, newblk);
516 newblk = 0;
517 }
518 else
519 ret = remove_tree(dquot, &newblk, depth+1);
520 if (ret >= 0 && !newblk) {
521 int i;
522 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
523 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */
Niu YaWeie821d942005-04-16 15:25:47 -0700524 /* Don't put the root block into the free block list */
525 if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 put_free_dqblk(sb, type, buf, *blk);
527 *blk = 0;
528 }
529 else
530 if ((ret = write_blk(sb, type, *blk, buf)) < 0)
531 printk(KERN_ERR "VFS: Can't write quota tree "
532 "block %u.\n", *blk);
533 }
534out_buf:
535 freedqbuf(buf);
536 return ret;
537}
538
539/* Delete dquot from tree */
540static int v2_delete_dquot(struct dquot *dquot)
541{
542 uint tmp = V2_DQTREEOFF;
543
544 if (!dquot->dq_off) /* Even not allocated? */
545 return 0;
546 return remove_tree(dquot, &tmp, 0);
547}
548
549/* Find entry in block */
550static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
551{
552 dqbuf_t buf = getdqbuf();
553 loff_t ret = 0;
554 int i;
555 struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
556
557 if (!buf)
558 return -ENOMEM;
559 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
560 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
561 goto out_buf;
562 }
563 if (dquot->dq_id)
564 for (i = 0; i < V2_DQSTRINBLK &&
565 le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
566 else { /* ID 0 as a bit more complicated searching... */
567 struct v2_disk_dqblk fakedquot;
568
569 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
570 for (i = 0; i < V2_DQSTRINBLK; i++)
571 if (!le32_to_cpu(ddquot[i].dqb_id) &&
572 memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
573 break;
574 }
575 if (i == V2_DQSTRINBLK) {
576 printk(KERN_ERR "VFS: Quota for id %u referenced "
577 "but not present.\n", dquot->dq_id);
578 ret = -EIO;
579 goto out_buf;
580 }
581 else
582 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
583 v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
584out_buf:
585 freedqbuf(buf);
586 return ret;
587}
588
589/* Find entry for given id in the tree */
590static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
591{
592 dqbuf_t buf = getdqbuf();
593 loff_t ret = 0;
594 __le32 *ref = (__le32 *)buf;
595
596 if (!buf)
597 return -ENOMEM;
598 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
599 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
600 goto out_buf;
601 }
602 ret = 0;
603 blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
604 if (!blk) /* No reference? */
605 goto out_buf;
606 if (depth < V2_DQTREEDEPTH-1)
607 ret = find_tree_dqentry(dquot, blk, depth+1);
608 else
609 ret = find_block_dqentry(dquot, blk);
610out_buf:
611 freedqbuf(buf);
612 return ret;
613}
614
615/* Find entry for given id in the tree - wrapper function */
616static inline loff_t find_dqentry(struct dquot *dquot)
617{
618 return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
619}
620
621static int v2_read_dquot(struct dquot *dquot)
622{
623 int type = dquot->dq_type;
624 loff_t offset;
625 struct v2_disk_dqblk ddquot, empty;
626 int ret = 0;
627
628#ifdef __QUOTA_V2_PARANOIA
629 /* Invalidated quota? */
630 if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) {
631 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
632 return -EIO;
633 }
634#endif
635 offset = find_dqentry(dquot);
636 if (offset <= 0) { /* Entry not present? */
637 if (offset < 0)
638 printk(KERN_ERR "VFS: Can't read quota "
639 "structure for id %u.\n", dquot->dq_id);
640 dquot->dq_off = 0;
641 set_bit(DQ_FAKE_B, &dquot->dq_flags);
642 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
643 ret = offset;
644 }
645 else {
646 dquot->dq_off = offset;
647 if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
648 (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
649 != sizeof(struct v2_disk_dqblk)) {
650 if (ret >= 0)
651 ret = -EIO;
652 printk(KERN_ERR "VFS: Error while reading quota "
653 "structure for id %u.\n", dquot->dq_id);
654 memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
655 }
656 else {
657 ret = 0;
658 /* We need to escape back all-zero structure */
659 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
660 empty.dqb_itime = cpu_to_le64(1);
661 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
662 ddquot.dqb_itime = 0;
663 }
664 disk2memdqb(&dquot->dq_dqb, &ddquot);
665 if (!dquot->dq_dqb.dqb_bhardlimit &&
666 !dquot->dq_dqb.dqb_bsoftlimit &&
667 !dquot->dq_dqb.dqb_ihardlimit &&
668 !dquot->dq_dqb.dqb_isoftlimit)
669 set_bit(DQ_FAKE_B, &dquot->dq_flags);
670 }
671 dqstats.reads++;
672
673 return ret;
674}
675
676/* Check whether dquot should not be deleted. We know we are
677 * the only one operating on dquot (thanks to dq_lock) */
678static int v2_release_dquot(struct dquot *dquot)
679{
680 if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
681 return v2_delete_dquot(dquot);
682 return 0;
683}
684
685static struct quota_format_ops v2_format_ops = {
686 .check_quota_file = v2_check_quota_file,
687 .read_file_info = v2_read_file_info,
688 .write_file_info = v2_write_file_info,
689 .free_file_info = NULL,
690 .read_dqblk = v2_read_dquot,
691 .commit_dqblk = v2_write_dquot,
692 .release_dqblk = v2_release_dquot,
693};
694
695static struct quota_format_type v2_quota_format = {
696 .qf_fmt_id = QFMT_VFS_V0,
697 .qf_ops = &v2_format_ops,
698 .qf_owner = THIS_MODULE
699};
700
701static int __init init_v2_quota_format(void)
702{
703 return register_quota_format(&v2_quota_format);
704}
705
706static void __exit exit_v2_quota_format(void)
707{
708 unregister_quota_format(&v2_quota_format);
709}
710
711module_init(init_v2_quota_format);
712module_exit(exit_v2_quota_format);