FreeBSD/Linux Kernel Cross Reference
sys/fs/quota_v2.c
1 /*
2 * vfsv0 quota IO operations on file
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
19 typedef 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 /* Check whether given file is really vfsv0 quotafile */
25 static 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 /* Read information header from quota file */
48 static 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 kdevname(f->f_dentry->d_sb->s_dev));
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 /* Write information header to quota file */
76 static 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 kdevname(f->f_dentry->d_sb->s_dev));
99 return -1;
100 }
101 return 0;
102 }
103
104 static 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
116 static 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
129 static 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
137 static inline void freedqbuf(dqbuf_t buf)
138 {
139 kfree(buf);
140 }
141
142 static 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
156 static 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 /* Remove empty block from list and return it */
171 static 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) /* Assure block allocation... */
188 goto out_buf;
189 blk = info->u.v2_i.dqi_blocks++;
190 }
191 mark_info_dirty(info);
192 ret = blk;
193 out_buf:
194 freedqbuf(buf);
195 return ret;
196 }
197
198 /* Insert empty block to the list */
199 static 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) /* Some strange block. We had better leave it... */
210 return err;
211 return 0;
212 }
213
214 /* Remove given block from the list of blocks with free entries */
215 static 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) /* No matter whether write succeeds block is out of list */
245 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
246 return 0;
247 out_buf:
248 freedqbuf(tmpbuf);
249 return err;
250 }
251
252 /* Insert given block to the beginning of list with free entries */
253 static 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;
276 out_buf:
277 freedqbuf(tmpbuf);
278 return err;
279 }
280
281 /* Find space for dquot */
282 static 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; /* This is enough as block is already zeroed and entry list is empty... */
312 mark_info_dirty(info);
313 }
314 if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */
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 /* Find free structure in block */
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;
337 out_buf:
338 freedqbuf(buf);
339 return 0;
340 }
341
342 /* Insert reference to structure into the trie */
343 static 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);
390 out_buf:
391 freedqbuf(buf);
392 return ret;
393 }
394
395 /* Wrapper for inserting quota structure into tree */
396 static 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 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
404 */
405 static 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 %d 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", kdevname(dquot->dq_dev));
428 if (ret >= 0)
429 ret = -ENOSPC;
430 }
431 else
432 ret = 0;
433 dqstats.writes++;
434 return ret;
435 }
436
437 /* Free dquot entry in data block */
438 static int free_dqentry(struct dquot *dquot, uint blk)
439 {
440 struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
441 struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
442 struct v2_disk_dqdbheader *dh;
443 dqbuf_t buf = getdqbuf();
444 int ret = 0;
445
446 if (!buf)
447 return -ENOMEM;
448 if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
449 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));
450 goto out_buf;
451 }
452 if ((ret = read_blk(filp, blk, buf)) < 0) {
453 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
454 goto out_buf;
455 }
456 dh = (struct v2_disk_dqdbheader *)buf;
457 dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
458 if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
459 if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
460 (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
461 printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
462 goto out_buf;
463 }
464 }
465 else {
466 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk));
467 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
468 /* Insert will write block itself */
469 if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) {
470 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
471 goto out_buf;
472 }
473 }
474 else
475 if ((ret = write_blk(filp, blk, buf)) < 0) {
476 printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);
477 goto out_buf;
478 }
479 }
480 dquot->dq_off = 0; /* Quota is now unattached */
481 out_buf:
482 freedqbuf(buf);
483 return ret;
484 }
485
486 /* Remove reference to dquot from tree */
487 static int remove_tree(struct dquot *dquot, uint *blk, int depth)
488 {
489 struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
490 struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
491 dqbuf_t buf = getdqbuf();
492 int ret = 0;
493 uint newblk;
494 u32 *ref = (u32 *)buf;
495
496 if (!buf)
497 return -ENOMEM;
498 if ((ret = read_blk(filp, *blk, buf)) < 0) {
499 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
500 goto out_buf;
501 }
502 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
503 if (depth == V2_DQTREEDEPTH-1) {
504 ret = free_dqentry(dquot, newblk);
505 newblk = 0;
506 }
507 else
508 ret = remove_tree(dquot, &newblk, depth+1);
509 if (ret >= 0 && !newblk) {
510 int i;
511 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
512 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */
513 if (i == V2_DQBLKSIZE) {
514 put_free_dqblk(filp, info, buf, *blk);
515 *blk = 0;
516 }
517 else
518 if ((ret = write_blk(filp, *blk, buf)) < 0)
519 printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);
520 }
521 out_buf:
522 freedqbuf(buf);
523 return ret;
524 }
525
526 /* Delete dquot from tree */
527 static int v2_delete_dquot(struct dquot *dquot)
528 {
529 uint tmp = V2_DQTREEOFF;
530
531 if (!dquot->dq_off) /* Even not allocated? */
532 return 0;
533 return remove_tree(dquot, &tmp, 0);
534 }
535
536 /* Find entry in block */
537 static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
538 {
539 struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
540 dqbuf_t buf = getdqbuf();
541 loff_t ret = 0;
542 int i;
543 struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
544
545 if (!buf)
546 return -ENOMEM;
547 if ((ret = read_blk(filp, blk, buf)) < 0) {
548 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
549 goto out_buf;
550 }
551 if (dquot->dq_id)
552 for (i = 0; i < V2_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
553 else { /* ID 0 as a bit more complicated searching... */
554 struct v2_disk_dqblk fakedquot;
555
556 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
557 for (i = 0; i < V2_DQSTRINBLK; i++)
558 if (!le32_to_cpu(ddquot[i].dqb_id) && 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 but not present.\n", dquot->dq_id);
563 ret = -EIO;
564 goto out_buf;
565 }
566 else
567 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
568 out_buf:
569 freedqbuf(buf);
570 return ret;
571 }
572
573 /* Find entry for given id in the tree */
574 static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
575 {
576 struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
577 dqbuf_t buf = getdqbuf();
578 loff_t ret = 0;
579 u32 *ref = (u32 *)buf;
580
581 if (!buf)
582 return -ENOMEM;
583 if ((ret = read_blk(filp, blk, buf)) < 0) {
584 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
585 goto out_buf;
586 }
587 ret = 0;
588 blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
589 if (!blk) /* No reference? */
590 goto out_buf;
591 if (depth < V2_DQTREEDEPTH-1)
592 ret = find_tree_dqentry(dquot, blk, depth+1);
593 else
594 ret = find_block_dqentry(dquot, blk);
595 out_buf:
596 freedqbuf(buf);
597 return ret;
598 }
599
600 /* Find entry for given id in the tree - wrapper function */
601 static inline loff_t find_dqentry(struct dquot *dquot)
602 {
603 return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
604 }
605
606 static int v2_read_dquot(struct dquot *dquot)
607 {
608 int type = dquot->dq_type;
609 struct file *filp;
610 mm_segment_t fs;
611 loff_t offset;
612 struct v2_disk_dqblk ddquot;
613 int ret = 0;
614
615 filp = sb_dqopt(dquot->dq_sb)->files[type];
616
617 #ifdef __QUOTA_V2_PARANOIA
618 if (!filp || !dquot->dq_sb) { /* Invalidated quota? */
619 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
620 return -EIO;
621 }
622 #endif
623 offset = find_dqentry(dquot);
624 if (offset <= 0) { /* Entry not present? */
625 if (offset < 0)
626 printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
627 dquot->dq_off = 0;
628 dquot->dq_flags |= DQ_FAKE;
629 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
630 ret = offset;
631 }
632 else {
633 dquot->dq_off = offset;
634 fs = get_fs();
635 set_fs(KERNEL_DS);
636 if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset)) != sizeof(struct v2_disk_dqblk)) {
637 if (ret >= 0)
638 ret = -EIO;
639 printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id);
640 memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
641 }
642 else
643 ret = 0;
644 set_fs(fs);
645 disk2memdqb(&dquot->dq_dqb, &ddquot);
646 }
647 dqstats.reads++;
648 return ret;
649 }
650
651 /* Commit changes of dquot to disk - it might also mean deleting it when quota became fake one and user has no blocks... */
652 static int v2_commit_dquot(struct dquot *dquot)
653 {
654 /* We clear the flag everytime so we don't loop when there was an IO error... */
655 dquot->dq_flags &= ~DQ_MOD;
656 if (dquot->dq_flags & DQ_FAKE && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
657 return v2_delete_dquot(dquot);
658 else
659 return v2_write_dquot(dquot);
660 }
661
662 static struct quota_format_ops v2_format_ops = {
663 check_quota_file: v2_check_quota_file,
664 read_file_info: v2_read_file_info,
665 write_file_info: v2_write_file_info,
666 free_file_info: NULL,
667 read_dqblk: v2_read_dquot,
668 commit_dqblk: v2_commit_dquot,
669 };
670
671 static struct quota_format_type v2_quota_format = {
672 qf_fmt_id: QFMT_VFS_V0,
673 qf_ops: &v2_format_ops,
674 qf_owner: THIS_MODULE
675 };
676
677 static int __init init_v2_quota_format(void)
678 {
679 return register_quota_format(&v2_quota_format);
680 }
681
682 static void __exit exit_v2_quota_format(void)
683 {
684 unregister_quota_format(&v2_quota_format);
685 }
686
687 EXPORT_NO_SYMBOLS;
688
689 module_init(init_v2_quota_format);
690 module_exit(exit_v2_quota_format);
Cache object: 8883c3e3ec5fea443d1458b4c46cbe0e
|