aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2008-09-21 23:54:49 -0400
committerMark Fasheh <mfasheh@suse.com>2009-01-05 11:40:21 -0500
commit1ccd14b9c271c1ac6eec5c5ec5def433100e7248 (patch)
tree959756aa5b68c568a18697464df3f0acdd0387cf
parentcf770c137122b78470a67ebd5498947869a09197 (diff)
quota: Split off quota tree handling into a separate file
There is going to be a new version of quota format having 64-bit quota limits and a new quota format for OCFS2. They are both going to use the same tree structure as VFSv0 quota format. So split out tree handling into a separate file and make size of leaf blocks, amount of space usable in each block (needed for checksumming) and structures contained in them configurable so that the code can be shared. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
-rw-r--r--fs/Kconfig5
-rw-r--r--fs/Makefile1
-rw-r--r--fs/quota_tree.c645
-rw-r--r--fs/quota_tree.h25
-rw-r--r--fs/quota_v2.c596
-rw-r--r--fs/quotaio_v2.h33
-rw-r--r--include/linux/dqblk_qtree.h56
-rw-r--r--include/linux/dqblk_v2.h19
8 files changed, 799 insertions, 581 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index b93425ad15de..c1ce3d8831d8 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -302,6 +302,10 @@ config PRINT_QUOTA_WARNING
302 Note that this behavior is currently deprecated and may go away in 302 Note that this behavior is currently deprecated and may go away in
303 future. Please use notification via netlink socket instead. 303 future. Please use notification via netlink socket instead.
304 304
305# Generic support for tree structured quota files. Seleted when needed.
306config QUOTA_TREE
307 tristate
308
305config QFMT_V1 309config QFMT_V1
306 tristate "Old quota format support" 310 tristate "Old quota format support"
307 depends on QUOTA 311 depends on QUOTA
@@ -313,6 +317,7 @@ config QFMT_V1
313config QFMT_V2 317config QFMT_V2
314 tristate "Quota format v2 support" 318 tristate "Quota format v2 support"
315 depends on QUOTA 319 depends on QUOTA
320 select QUOTA_TREE
316 help 321 help
317 This quota format allows using quotas with 32-bit UIDs/GIDs. If you 322 This quota format allows using quotas with 32-bit UIDs/GIDs. If you
318 need this functionality say Y here. 323 need this functionality say Y here.
diff --git a/fs/Makefile b/fs/Makefile
index e6f423d1d228..c830611550d3 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
54obj-$(CONFIG_QUOTA) += dquot.o 54obj-$(CONFIG_QUOTA) += dquot.o
55obj-$(CONFIG_QFMT_V1) += quota_v1.o 55obj-$(CONFIG_QFMT_V1) += quota_v1.o
56obj-$(CONFIG_QFMT_V2) += quota_v2.o 56obj-$(CONFIG_QFMT_V2) += quota_v2.o
57obj-$(CONFIG_QUOTA_TREE) += quota_tree.o
57obj-$(CONFIG_QUOTACTL) += quota.o 58obj-$(CONFIG_QUOTACTL) += quota.o
58 59
59obj-$(CONFIG_PROC_FS) += proc/ 60obj-$(CONFIG_PROC_FS) += proc/
diff --git a/fs/quota_tree.c b/fs/quota_tree.c
new file mode 100644
index 000000000000..953404c95b17
--- /dev/null
+++ b/fs/quota_tree.c
@@ -0,0 +1,645 @@
1/*
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/kernel.h>
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/slab.h>
13#include <linux/quotaops.h>
14
15#include <asm/byteorder.h>
16
17#include "quota_tree.h"
18
19MODULE_AUTHOR("Jan Kara");
20MODULE_DESCRIPTION("Quota trie support");
21MODULE_LICENSE("GPL");
22
23#define __QUOTA_QT_PARANOIA
24
25typedef char *dqbuf_t;
26
27static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
28{
29 unsigned int epb = info->dqi_usable_bs >> 2;
30
31 depth = info->dqi_qtree_depth - depth - 1;
32 while (depth--)
33 id /= epb;
34 return id % epb;
35}
36
37/* Number of entries in one blocks */
38static inline int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info)
39{
40 return (info->dqi_usable_bs - sizeof(struct qt_disk_dqdbheader))
41 / info->dqi_entry_size;
42}
43
44static dqbuf_t getdqbuf(size_t size)
45{
46 dqbuf_t buf = kmalloc(size, GFP_NOFS);
47 if (!buf)
48 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
49 return buf;
50}
51
52static inline void freedqbuf(dqbuf_t buf)
53{
54 kfree(buf);
55}
56
57static inline ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, dqbuf_t buf)
58{
59 struct super_block *sb = info->dqi_sb;
60
61 memset(buf, 0, info->dqi_usable_bs);
62 return sb->s_op->quota_read(sb, info->dqi_type, (char *)buf,
63 info->dqi_usable_bs, blk << info->dqi_blocksize_bits);
64}
65
66static inline ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, dqbuf_t buf)
67{
68 struct super_block *sb = info->dqi_sb;
69
70 return sb->s_op->quota_write(sb, info->dqi_type, (char *)buf,
71 info->dqi_usable_bs, blk << info->dqi_blocksize_bits);
72}
73
74/* Remove empty block from list and return it */
75static int get_free_dqblk(struct qtree_mem_dqinfo *info)
76{
77 dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
78 struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
79 int ret, blk;
80
81 if (!buf)
82 return -ENOMEM;
83 if (info->dqi_free_blk) {
84 blk = info->dqi_free_blk;
85 ret = read_blk(info, blk, buf);
86 if (ret < 0)
87 goto out_buf;
88 info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
89 }
90 else {
91 memset(buf, 0, info->dqi_usable_bs);
92 /* Assure block allocation... */
93 ret = write_blk(info, info->dqi_blocks, buf);
94 if (ret < 0)
95 goto out_buf;
96 blk = info->dqi_blocks++;
97 }
98 mark_info_dirty(info->dqi_sb, info->dqi_type);
99 ret = blk;
100out_buf:
101 freedqbuf(buf);
102 return ret;
103}
104
105/* Insert empty block to the list */
106static int put_free_dqblk(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk)
107{
108 struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
109 int err;
110
111 dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
112 dh->dqdh_prev_free = cpu_to_le32(0);
113 dh->dqdh_entries = cpu_to_le16(0);
114 err = write_blk(info, blk, buf);
115 if (err < 0)
116 return err;
117 info->dqi_free_blk = blk;
118 mark_info_dirty(info->dqi_sb, info->dqi_type);
119 return 0;
120}
121
122/* Remove given block from the list of blocks with free entries */
123static int remove_free_dqentry(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk)
124{
125 dqbuf_t tmpbuf = getdqbuf(info->dqi_usable_bs);
126 struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
127 uint nextblk = le32_to_cpu(dh->dqdh_next_free);
128 uint prevblk = le32_to_cpu(dh->dqdh_prev_free);
129 int err;
130
131 if (!tmpbuf)
132 return -ENOMEM;
133 if (nextblk) {
134 err = read_blk(info, nextblk, tmpbuf);
135 if (err < 0)
136 goto out_buf;
137 ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
138 dh->dqdh_prev_free;
139 err = write_blk(info, nextblk, tmpbuf);
140 if (err < 0)
141 goto out_buf;
142 }
143 if (prevblk) {
144 err = read_blk(info, prevblk, tmpbuf);
145 if (err < 0)
146 goto out_buf;
147 ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free =
148 dh->dqdh_next_free;
149 err = write_blk(info, prevblk, tmpbuf);
150 if (err < 0)
151 goto out_buf;
152 } else {
153 info->dqi_free_entry = nextblk;
154 mark_info_dirty(info->dqi_sb, info->dqi_type);
155 }
156 freedqbuf(tmpbuf);
157 dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
158 /* No matter whether write succeeds block is out of list */
159 if (write_blk(info, blk, buf) < 0)
160 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
161 return 0;
162out_buf:
163 freedqbuf(tmpbuf);
164 return err;
165}
166
167/* Insert given block to the beginning of list with free entries */
168static int insert_free_dqentry(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk)
169{
170 dqbuf_t tmpbuf = getdqbuf(info->dqi_usable_bs);
171 struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
172 int err;
173
174 if (!tmpbuf)
175 return -ENOMEM;
176 dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
177 dh->dqdh_prev_free = cpu_to_le32(0);
178 err = write_blk(info, blk, buf);
179 if (err < 0)
180 goto out_buf;
181 if (info->dqi_free_entry) {
182 err = read_blk(info, info->dqi_free_entry, tmpbuf);
183 if (err < 0)
184 goto out_buf;
185 ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
186 cpu_to_le32(blk);
187 err = write_blk(info, info->dqi_free_entry, tmpbuf);
188 if (err < 0)
189 goto out_buf;
190 }
191 freedqbuf(tmpbuf);
192 info->dqi_free_entry = blk;
193 mark_info_dirty(info->dqi_sb, info->dqi_type);
194 return 0;
195out_buf:
196 freedqbuf(tmpbuf);
197 return err;
198}
199
200/* Is the entry in the block free? */
201int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk)
202{
203 int i;
204
205 for (i = 0; i < info->dqi_entry_size; i++)
206 if (disk[i])
207 return 0;
208 return 1;
209}
210EXPORT_SYMBOL(qtree_entry_unused);
211
212/* Find space for dquot */
213static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
214 struct dquot *dquot, int *err)
215{
216 uint blk, i;
217 struct qt_disk_dqdbheader *dh;
218 dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
219 char *ddquot;
220
221 *err = 0;
222 if (!buf) {
223 *err = -ENOMEM;
224 return 0;
225 }
226 dh = (struct qt_disk_dqdbheader *)buf;
227 if (info->dqi_free_entry) {
228 blk = info->dqi_free_entry;
229 *err = read_blk(info, blk, buf);
230 if (*err < 0)
231 goto out_buf;
232 } else {
233 blk = get_free_dqblk(info);
234 if ((int)blk < 0) {
235 *err = blk;
236 freedqbuf(buf);
237 return 0;
238 }
239 memset(buf, 0, info->dqi_usable_bs);
240 /* This is enough as block is already zeroed and entry list is empty... */
241 info->dqi_free_entry = blk;
242 mark_info_dirty(dquot->dq_sb, dquot->dq_type);
243 }
244 /* Block will be full? */
245 if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) {
246 *err = remove_free_dqentry(info, buf, blk);
247 if (*err < 0) {
248 printk(KERN_ERR "VFS: find_free_dqentry(): Can't "
249 "remove block (%u) from entry free list.\n",
250 blk);
251 goto out_buf;
252 }
253 }
254 le16_add_cpu(&dh->dqdh_entries, 1);
255 /* Find free structure in block */
256 for (i = 0, ddquot = ((char *)buf) + sizeof(struct qt_disk_dqdbheader);
257 i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot);
258 i++, ddquot += info->dqi_entry_size);
259#ifdef __QUOTA_QT_PARANOIA
260 if (i == qtree_dqstr_in_blk(info)) {
261 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full "
262 "but it shouldn't.\n");
263 *err = -EIO;
264 goto out_buf;
265 }
266#endif
267 *err = write_blk(info, blk, buf);
268 if (*err < 0) {
269 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota "
270 "data block %u.\n", blk);
271 goto out_buf;
272 }
273 dquot->dq_off = (blk << info->dqi_blocksize_bits) +
274 sizeof(struct qt_disk_dqdbheader) +
275 i * info->dqi_entry_size;
276 freedqbuf(buf);
277 return blk;
278out_buf:
279 freedqbuf(buf);
280 return 0;
281}
282
283/* Insert reference to structure into the trie */
284static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
285 uint *treeblk, int depth)
286{
287 dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
288 int ret = 0, newson = 0, newact = 0;
289 __le32 *ref;
290 uint newblk;
291
292 if (!buf)
293 return -ENOMEM;
294 if (!*treeblk) {
295 ret = get_free_dqblk(info);
296 if (ret < 0)
297 goto out_buf;
298 *treeblk = ret;
299 memset(buf, 0, info->dqi_usable_bs);
300 newact = 1;
301 } else {
302 ret = read_blk(info, *treeblk, buf);
303 if (ret < 0) {
304 printk(KERN_ERR "VFS: Can't read tree quota block "
305 "%u.\n", *treeblk);
306 goto out_buf;
307 }
308 }
309 ref = (__le32 *)buf;
310 newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
311 if (!newblk)
312 newson = 1;
313 if (depth == info->dqi_qtree_depth - 1) {
314#ifdef __QUOTA_QT_PARANOIA
315 if (newblk) {
316 printk(KERN_ERR "VFS: Inserting already present quota "
317 "entry (block %u).\n",
318 le32_to_cpu(ref[get_index(info,
319 dquot->dq_id, depth)]));
320 ret = -EIO;
321 goto out_buf;
322 }
323#endif
324 newblk = find_free_dqentry(info, dquot, &ret);
325 } else {
326 ret = do_insert_tree(info, dquot, &newblk, depth+1);
327 }
328 if (newson && ret >= 0) {
329 ref[get_index(info, dquot->dq_id, depth)] =
330 cpu_to_le32(newblk);
331 ret = write_blk(info, *treeblk, buf);
332 } else if (newact && ret < 0) {
333 put_free_dqblk(info, buf, *treeblk);
334 }
335out_buf:
336 freedqbuf(buf);
337 return ret;
338}
339
340/* Wrapper for inserting quota structure into tree */
341static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
342 struct dquot *dquot)
343{
344 int tmp = QT_TREEOFF;
345 return do_insert_tree(info, dquot, &tmp, 0);
346}
347
348/*
349 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
350 */
351int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
352{
353 int type = dquot->dq_type;
354 struct super_block *sb = dquot->dq_sb;
355 ssize_t ret;
356 dqbuf_t ddquot = getdqbuf(info->dqi_entry_size);
357
358 if (!ddquot)
359 return -ENOMEM;
360
361 /* dq_off is guarded by dqio_mutex */
362 if (!dquot->dq_off) {
363 ret = dq_insert_tree(info, dquot);
364 if (ret < 0) {
365 printk(KERN_ERR "VFS: Error %zd occurred while "
366 "creating quota.\n", ret);
367 freedqbuf(ddquot);
368 return ret;
369 }
370 }
371 spin_lock(&dq_data_lock);
372 info->dqi_ops->mem2disk_dqblk(ddquot, dquot);
373 spin_unlock(&dq_data_lock);
374 ret = sb->s_op->quota_write(sb, type, (char *)ddquot,
375 info->dqi_entry_size, dquot->dq_off);
376 if (ret != info->dqi_entry_size) {
377 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
378 sb->s_id);
379 if (ret >= 0)
380 ret = -ENOSPC;
381 } else {
382 ret = 0;
383 }
384 dqstats.writes++;
385 freedqbuf(ddquot);
386
387 return ret;
388}
389EXPORT_SYMBOL(qtree_write_dquot);
390
391/* Free dquot entry in data block */
392static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
393 uint blk)
394{
395 struct qt_disk_dqdbheader *dh;
396 dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
397 int ret = 0;
398
399 if (!buf)
400 return -ENOMEM;
401 if (dquot->dq_off >> info->dqi_blocksize_bits != blk) {
402 printk(KERN_ERR "VFS: Quota structure has offset to other "
403 "block (%u) than it should (%u).\n", blk,
404 (uint)(dquot->dq_off >> info->dqi_blocksize_bits));
405 goto out_buf;
406 }
407 ret = read_blk(info, blk, buf);
408 if (ret < 0) {
409 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
410 goto out_buf;
411 }
412 dh = (struct qt_disk_dqdbheader *)buf;
413 le16_add_cpu(&dh->dqdh_entries, -1);
414 if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
415 ret = remove_free_dqentry(info, buf, blk);
416 if (ret >= 0)
417 ret = put_free_dqblk(info, buf, blk);
418 if (ret < 0) {
419 printk(KERN_ERR "VFS: Can't move quota data block (%u) "
420 "to free list.\n", blk);
421 goto out_buf;
422 }
423 } else {
424 memset(buf +
425 (dquot->dq_off & ((1 << info->dqi_blocksize_bits) - 1)),
426 0, info->dqi_entry_size);
427 if (le16_to_cpu(dh->dqdh_entries) ==
428 qtree_dqstr_in_blk(info) - 1) {
429 /* Insert will write block itself */
430 ret = insert_free_dqentry(info, buf, blk);
431 if (ret < 0) {
432 printk(KERN_ERR "VFS: Can't insert quota data "
433 "block (%u) to free entry list.\n", blk);
434 goto out_buf;
435 }
436 } else {
437 ret = write_blk(info, blk, buf);
438 if (ret < 0) {
439 printk(KERN_ERR "VFS: Can't write quota data "
440 "block %u\n", blk);
441 goto out_buf;
442 }
443 }
444 }
445 dquot->dq_off = 0; /* Quota is now unattached */
446out_buf:
447 freedqbuf(buf);
448 return ret;
449}
450
451/* Remove reference to dquot from tree */
452static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
453 uint *blk, int depth)
454{
455 dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
456 int ret = 0;
457 uint newblk;
458 __le32 *ref = (__le32 *)buf;
459
460 if (!buf)
461 return -ENOMEM;
462 ret = read_blk(info, *blk, buf);
463 if (ret < 0) {
464 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
465 goto out_buf;
466 }
467 newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
468 if (depth == info->dqi_qtree_depth - 1) {
469 ret = free_dqentry(info, dquot, newblk);
470 newblk = 0;
471 } else {
472 ret = remove_tree(info, dquot, &newblk, depth+1);
473 }
474 if (ret >= 0 && !newblk) {
475 int i;
476 ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0);
477 /* Block got empty? */
478 for (i = 0;
479 i < (info->dqi_usable_bs >> 2) && !ref[i];
480 i++);
481 /* Don't put the root block into the free block list */
482 if (i == (info->dqi_usable_bs >> 2)
483 && *blk != QT_TREEOFF) {
484 put_free_dqblk(info, buf, *blk);
485 *blk = 0;
486 } else {
487 ret = write_blk(info, *blk, buf);
488 if (ret < 0)
489 printk(KERN_ERR "VFS: Can't write quota tree "
490 "block %u.\n", *blk);
491 }
492 }
493out_buf:
494 freedqbuf(buf);
495 return ret;
496}
497
498/* Delete dquot from tree */
499int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
500{
501 uint tmp = QT_TREEOFF;
502
503 if (!dquot->dq_off) /* Even not allocated? */
504 return 0;
505 return remove_tree(info, dquot, &tmp, 0);
506}
507EXPORT_SYMBOL(qtree_delete_dquot);
508
509/* Find entry in block */
510static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
511 struct dquot *dquot, uint blk)
512{
513 dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
514 loff_t ret = 0;
515 int i;
516 char *ddquot;
517
518 if (!buf)
519 return -ENOMEM;
520 ret = read_blk(info, blk, buf);
521 if (ret < 0) {
522 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
523 goto out_buf;
524 }
525 for (i = 0, ddquot = ((char *)buf) + sizeof(struct qt_disk_dqdbheader);
526 i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot);
527 i++, ddquot += info->dqi_entry_size);
528 if (i == qtree_dqstr_in_blk(info)) {
529 printk(KERN_ERR "VFS: Quota for id %u referenced "
530 "but not present.\n", dquot->dq_id);
531 ret = -EIO;
532 goto out_buf;
533 } else {
534 ret = (blk << info->dqi_blocksize_bits) + sizeof(struct
535 qt_disk_dqdbheader) + i * info->dqi_entry_size;
536 }
537out_buf:
538 freedqbuf(buf);
539 return ret;
540}
541
542/* Find entry for given id in the tree */
543static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
544 struct dquot *dquot, uint blk, int depth)
545{
546 dqbuf_t buf = getdqbuf(info->dqi_usable_bs);
547 loff_t ret = 0;
548 __le32 *ref = (__le32 *)buf;
549
550 if (!buf)
551 return -ENOMEM;
552 ret = read_blk(info, blk, buf);
553 if (ret < 0) {
554 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
555 goto out_buf;
556 }
557 ret = 0;
558 blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
559 if (!blk) /* No reference? */
560 goto out_buf;
561 if (depth < info->dqi_qtree_depth - 1)
562 ret = find_tree_dqentry(info, dquot, blk, depth+1);
563 else
564 ret = find_block_dqentry(info, dquot, blk);
565out_buf:
566 freedqbuf(buf);
567 return ret;
568}
569
570/* Find entry for given id in the tree - wrapper function */
571static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info,
572 struct dquot *dquot)
573{
574 return find_tree_dqentry(info, dquot, QT_TREEOFF, 0);
575}
576
577int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
578{
579 int type = dquot->dq_type;
580 struct super_block *sb = dquot->dq_sb;
581 loff_t offset;
582 dqbuf_t ddquot;
583 int ret = 0;
584
585#ifdef __QUOTA_QT_PARANOIA
586 /* Invalidated quota? */
587 if (!sb_dqopt(dquot->dq_sb)->files[type]) {
588 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
589 return -EIO;
590 }
591#endif
592 /* Do we know offset of the dquot entry in the quota file? */
593 if (!dquot->dq_off) {
594 offset = find_dqentry(info, dquot);
595 if (offset <= 0) { /* Entry not present? */
596 if (offset < 0)
597 printk(KERN_ERR "VFS: Can't read quota "
598 "structure for id %u.\n", dquot->dq_id);
599 dquot->dq_off = 0;
600 set_bit(DQ_FAKE_B, &dquot->dq_flags);
601 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
602 ret = offset;
603 goto out;
604 }
605 dquot->dq_off = offset;
606 }
607 ddquot = getdqbuf(info->dqi_entry_size);
608 if (!ddquot)
609 return -ENOMEM;
610 ret = sb->s_op->quota_read(sb, type, (char *)ddquot,
611 info->dqi_entry_size, dquot->dq_off);
612 if (ret != info->dqi_entry_size) {
613 if (ret >= 0)
614 ret = -EIO;
615 printk(KERN_ERR "VFS: Error while reading quota "
616 "structure for id %u.\n", dquot->dq_id);
617 set_bit(DQ_FAKE_B, &dquot->dq_flags);
618 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
619 freedqbuf(ddquot);
620 goto out;
621 }
622 spin_lock(&dq_data_lock);
623 info->dqi_ops->disk2mem_dqblk(dquot, ddquot);
624 if (!dquot->dq_dqb.dqb_bhardlimit &&
625 !dquot->dq_dqb.dqb_bsoftlimit &&
626 !dquot->dq_dqb.dqb_ihardlimit &&
627 !dquot->dq_dqb.dqb_isoftlimit)
628 set_bit(DQ_FAKE_B, &dquot->dq_flags);
629 spin_unlock(&dq_data_lock);
630 freedqbuf(ddquot);
631out:
632 dqstats.reads++;
633 return ret;
634}
635EXPORT_SYMBOL(qtree_read_dquot);
636
637/* Check whether dquot should not be deleted. We know we are
638 * the only one operating on dquot (thanks to dq_lock) */
639int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
640{
641 if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
642 return qtree_delete_dquot(info, dquot);
643 return 0;
644}
645EXPORT_SYMBOL(qtree_release_dquot);
diff --git a/fs/quota_tree.h b/fs/quota_tree.h
new file mode 100644
index 000000000000..a1ab8db81a51
--- /dev/null
+++ b/fs/quota_tree.h
@@ -0,0 +1,25 @@
1/*
2 * Definitions of structures for vfsv0 quota format
3 */
4
5#ifndef _LINUX_QUOTA_TREE_H
6#define _LINUX_QUOTA_TREE_H
7
8#include <linux/types.h>
9#include <linux/quota.h>
10
11/*
12 * Structure of header of block with quota structures. It is padded to 16 bytes so
13 * there will be space for exactly 21 quota-entries in a block
14 */
15struct qt_disk_dqdbheader {
16 __le32 dqdh_next_free; /* Number of next block with free entry */
17 __le32 dqdh_prev_free; /* Number of previous block with free entry */
18 __le16 dqdh_entries; /* Number of valid entries in block */
19 __le16 dqdh_pad1;
20 __le32 dqdh_pad2;
21};
22
23#define QT_TREEOFF 1 /* Offset of tree in file in blocks */
24
25#endif /* _LINUX_QUOTAIO_TREE_H */
diff --git a/fs/quota_v2.c b/fs/quota_v2.c
index a21d1a7c356a..a87f1028a425 100644
--- a/fs/quota_v2.c
+++ b/fs/quota_v2.c
@@ -14,6 +14,7 @@
14 14
15#include <asm/byteorder.h> 15#include <asm/byteorder.h>
16 16
17#include "quota_tree.h"
17#include "quotaio_v2.h" 18#include "quotaio_v2.h"
18 19
19MODULE_AUTHOR("Jan Kara"); 20MODULE_AUTHOR("Jan Kara");
@@ -22,10 +23,15 @@ MODULE_LICENSE("GPL");
22 23
23#define __QUOTA_V2_PARANOIA 24#define __QUOTA_V2_PARANOIA
24 25
25typedef char *dqbuf_t; 26static void v2_mem2diskdqb(void *dp, struct dquot *dquot);
27static void v2_disk2memdqb(struct dquot *dquot, void *dp);
28static int v2_is_id(void *dp, struct dquot *dquot);
26 29
27#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff) 30static struct qtree_fmt_operations v2_qtree_ops = {
28#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader))) 31 .mem2disk_dqblk = v2_mem2diskdqb,
32 .disk2mem_dqblk = v2_disk2memdqb,
33 .is_id = v2_is_id,
34};
29 35
30#define QUOTABLOCK_BITS 10 36#define QUOTABLOCK_BITS 10
31#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) 37#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
@@ -64,7 +70,7 @@ static int v2_check_quota_file(struct super_block *sb, int type)
64static int v2_read_file_info(struct super_block *sb, int type) 70static int v2_read_file_info(struct super_block *sb, int type)
65{ 71{
66 struct v2_disk_dqinfo dinfo; 72 struct v2_disk_dqinfo dinfo;
67 struct mem_dqinfo *info = sb_dqopt(sb)->info+type; 73 struct mem_dqinfo *info = sb_dqinfo(sb, type);
68 ssize_t size; 74 ssize_t size;
69 75
70 size = sb->s_op->quota_read(sb, type, (char *)&dinfo, 76 size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
@@ -80,9 +86,16 @@ static int v2_read_file_info(struct super_block *sb, int type)
80 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); 86 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
81 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); 87 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
82 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); 88 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
83 info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); 89 info->u.v2_i.i.dqi_sb = sb;
84 info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); 90 info->u.v2_i.i.dqi_type = type;
85 info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); 91 info->u.v2_i.i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
92 info->u.v2_i.i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
93 info->u.v2_i.i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
94 info->u.v2_i.i.dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
95 info->u.v2_i.i.dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
96 info->u.v2_i.i.dqi_qtree_depth = qtree_depth(&info->u.v2_i.i);
97 info->u.v2_i.i.dqi_entry_size = sizeof(struct v2_disk_dqblk);
98 info->u.v2_i.i.dqi_ops = &v2_qtree_ops;
86 return 0; 99 return 0;
87} 100}
88 101
@@ -90,7 +103,7 @@ static int v2_read_file_info(struct super_block *sb, int type)
90static int v2_write_file_info(struct super_block *sb, int type) 103static int v2_write_file_info(struct super_block *sb, int type)
91{ 104{
92 struct v2_disk_dqinfo dinfo; 105 struct v2_disk_dqinfo dinfo;
93 struct mem_dqinfo *info = sb_dqopt(sb)->info+type; 106 struct mem_dqinfo *info = sb_dqinfo(sb, type);
94 ssize_t size; 107 ssize_t size;
95 108
96 spin_lock(&dq_data_lock); 109 spin_lock(&dq_data_lock);
@@ -99,9 +112,9 @@ static int v2_write_file_info(struct super_block *sb, int type)
99 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); 112 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
100 dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK); 113 dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
101 spin_unlock(&dq_data_lock); 114 spin_unlock(&dq_data_lock);
102 dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks); 115 dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.i.dqi_blocks);
103 dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk); 116 dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.i.dqi_free_blk);
104 dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry); 117 dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.i.dqi_free_entry);
105 size = sb->s_op->quota_write(sb, type, (char *)&dinfo, 118 size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
106 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); 119 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
107 if (size != sizeof(struct v2_disk_dqinfo)) { 120 if (size != sizeof(struct v2_disk_dqinfo)) {
@@ -112,8 +125,11 @@ static int v2_write_file_info(struct super_block *sb, int type)
112 return 0; 125 return 0;
113} 126}
114 127
115static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d) 128static void v2_disk2memdqb(struct dquot *dquot, void *dp)
116{ 129{
130 struct v2_disk_dqblk *d = dp, empty;
131 struct mem_dqblk *m = &dquot->dq_dqb;
132
117 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit); 133 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
118 m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit); 134 m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
119 m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes); 135 m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
@@ -122,10 +138,20 @@ static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
122 m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit)); 138 m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit));
123 m->dqb_curspace = le64_to_cpu(d->dqb_curspace); 139 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
124 m->dqb_btime = le64_to_cpu(d->dqb_btime); 140 m->dqb_btime = le64_to_cpu(d->dqb_btime);
141 /* We need to escape back all-zero structure */
142 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
143 empty.dqb_itime = cpu_to_le64(1);
144 if (!memcmp(&empty, dp, sizeof(struct v2_disk_dqblk)))
145 m->dqb_itime = 0;
125} 146}
126 147
127static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id) 148static void v2_mem2diskdqb(void *dp, struct dquot *dquot)
128{ 149{
150 struct v2_disk_dqblk *d = dp;
151 struct mem_dqblk *m = &dquot->dq_dqb;
152 struct qtree_mem_dqinfo *info =
153 &sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i;
154
129 d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit); 155 d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
130 d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); 156 d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
131 d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes); 157 d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
@@ -134,553 +160,35 @@ static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
134 d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit)); 160 d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
135 d->dqb_curspace = cpu_to_le64(m->dqb_curspace); 161 d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
136 d->dqb_btime = cpu_to_le64(m->dqb_btime); 162 d->dqb_btime = cpu_to_le64(m->dqb_btime);
137 d->dqb_id = cpu_to_le32(id); 163 d->dqb_id = cpu_to_le32(dquot->dq_id);
138} 164 if (qtree_entry_unused(info, dp))
139 165 d->dqb_itime = cpu_to_le64(1);
140static dqbuf_t getdqbuf(void)
141{
142 dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_NOFS);
143 if (!buf)
144 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
145 return buf;
146}
147
148static inline void freedqbuf(dqbuf_t buf)
149{
150 kfree(buf);
151}
152
153static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
154{
155 memset(buf, 0, V2_DQBLKSIZE);
156 return sb->s_op->quota_read(sb, type, (char *)buf,
157 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
158}
159
160static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
161{
162 return sb->s_op->quota_write(sb, type, (char *)buf,
163 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
164}
165
166/* Remove empty block from list and return it */
167static int get_free_dqblk(struct super_block *sb, int type)
168{
169 dqbuf_t buf = getdqbuf();
170 struct mem_dqinfo *info = sb_dqinfo(sb, type);
171 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
172 int ret, blk;
173
174 if (!buf)
175 return -ENOMEM;
176 if (info->u.v2_i.dqi_free_blk) {
177 blk = info->u.v2_i.dqi_free_blk;
178 if ((ret = read_blk(sb, type, blk, buf)) < 0)
179 goto out_buf;
180 info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
181 }
182 else {
183 memset(buf, 0, V2_DQBLKSIZE);
184 /* Assure block allocation... */
185 if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0)
186 goto out_buf;
187 blk = info->u.v2_i.dqi_blocks++;
188 }
189 mark_info_dirty(sb, type);
190 ret = blk;
191out_buf:
192 freedqbuf(buf);
193 return ret;
194}
195
196/* Insert empty block to the list */
197static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
198{
199 struct mem_dqinfo *info = sb_dqinfo(sb, type);
200 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
201 int err;
202
203 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk);
204 dh->dqdh_prev_free = cpu_to_le32(0);
205 dh->dqdh_entries = cpu_to_le16(0);
206 info->u.v2_i.dqi_free_blk = blk;
207 mark_info_dirty(sb, type);
208 /* Some strange block. We had better leave it... */
209 if ((err = write_blk(sb, type, blk, buf)) < 0)
210 return err;
211 return 0;
212} 166}
213 167
214/* Remove given block from the list of blocks with free entries */ 168static int v2_is_id(void *dp, struct dquot *dquot)
215static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
216{ 169{
217 dqbuf_t tmpbuf = getdqbuf(); 170 struct v2_disk_dqblk *d = dp;
218 struct mem_dqinfo *info = sb_dqinfo(sb, type); 171 struct qtree_mem_dqinfo *info =
219 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; 172 &sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i;
220 uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
221 int err;
222 173
223 if (!tmpbuf) 174 if (qtree_entry_unused(info, dp))
224 return -ENOMEM;
225 if (nextblk) {
226 if ((err = read_blk(sb, type, nextblk, tmpbuf)) < 0)
227 goto out_buf;
228 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
229 if ((err = write_blk(sb, type, nextblk, tmpbuf)) < 0)
230 goto out_buf;
231 }
232 if (prevblk) {
233 if ((err = read_blk(sb, type, prevblk, tmpbuf)) < 0)
234 goto out_buf;
235 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
236 if ((err = write_blk(sb, type, prevblk, tmpbuf)) < 0)
237 goto out_buf;
238 }
239 else {
240 info->u.v2_i.dqi_free_entry = nextblk;
241 mark_info_dirty(sb, type);
242 }
243 freedqbuf(tmpbuf);
244 dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
245 /* No matter whether write succeeds block is out of list */
246 if (write_blk(sb, type, blk, buf) < 0)
247 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
248 return 0;
249out_buf:
250 freedqbuf(tmpbuf);
251 return err;
252}
253
254/* Insert given block to the beginning of list with free entries */
255static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
256{
257 dqbuf_t tmpbuf = getdqbuf();
258 struct mem_dqinfo *info = sb_dqinfo(sb, type);
259 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
260 int err;
261
262 if (!tmpbuf)
263 return -ENOMEM;
264 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
265 dh->dqdh_prev_free = cpu_to_le32(0);
266 if ((err = write_blk(sb, type, blk, buf)) < 0)
267 goto out_buf;
268 if (info->u.v2_i.dqi_free_entry) {
269 if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
270 goto out_buf;
271 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
272 if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
273 goto out_buf;
274 }
275 freedqbuf(tmpbuf);
276 info->u.v2_i.dqi_free_entry = blk;
277 mark_info_dirty(sb, type);
278 return 0;
279out_buf:
280 freedqbuf(tmpbuf);
281 return err;
282}
283
284/* Find space for dquot */
285static uint find_free_dqentry(struct dquot *dquot, int *err)
286{
287 struct super_block *sb = dquot->dq_sb;
288 struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
289 uint blk, i;
290 struct v2_disk_dqdbheader *dh;
291 struct v2_disk_dqblk *ddquot;
292 struct v2_disk_dqblk fakedquot;
293 dqbuf_t buf;
294
295 *err = 0;
296 if (!(buf = getdqbuf())) {
297 *err = -ENOMEM;
298 return 0; 175 return 0;
299 } 176 return le32_to_cpu(d->dqb_id) == dquot->dq_id;
300 dh = (struct v2_disk_dqdbheader *)buf;
301 ddquot = GETENTRIES(buf);
302 if (info->u.v2_i.dqi_free_entry) {
303 blk = info->u.v2_i.dqi_free_entry;
304 if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0)
305 goto out_buf;
306 }
307 else {
308 blk = get_free_dqblk(sb, dquot->dq_type);
309 if ((int)blk < 0) {
310 *err = blk;
311 freedqbuf(buf);
312 return 0;
313 }
314 memset(buf, 0, V2_DQBLKSIZE);
315 /* This is enough as block is already zeroed and entry list is empty... */
316 info->u.v2_i.dqi_free_entry = blk;
317 mark_info_dirty(sb, dquot->dq_type);
318 }
319 if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */
320 if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
321 printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
322 goto out_buf;
323 }
324 le16_add_cpu(&dh->dqdh_entries, 1);
325 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
326 /* Find free structure in block */
327 for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
328#ifdef __QUOTA_V2_PARANOIA
329 if (i == V2_DQSTRINBLK) {
330 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
331 *err = -EIO;
332 goto out_buf;
333 }
334#endif
335 if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) {
336 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
337 goto out_buf;
338 }
339 dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
340 freedqbuf(buf);
341 return blk;
342out_buf:
343 freedqbuf(buf);
344 return 0;
345} 177}
346 178
347/* Insert reference to structure into the trie */ 179static int v2_read_dquot(struct dquot *dquot)
348static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
349{
350 struct super_block *sb = dquot->dq_sb;
351 dqbuf_t buf;
352 int ret = 0, newson = 0, newact = 0;
353 __le32 *ref;
354 uint newblk;
355
356 if (!(buf = getdqbuf()))
357 return -ENOMEM;
358 if (!*treeblk) {
359 ret = get_free_dqblk(sb, dquot->dq_type);
360 if (ret < 0)
361 goto out_buf;
362 *treeblk = ret;
363 memset(buf, 0, V2_DQBLKSIZE);
364 newact = 1;
365 }
366 else {
367 if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) {
368 printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
369 goto out_buf;
370 }
371 }
372 ref = (__le32 *)buf;
373 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
374 if (!newblk)
375 newson = 1;
376 if (depth == V2_DQTREEDEPTH-1) {
377#ifdef __QUOTA_V2_PARANOIA
378 if (newblk) {
379 printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]));
380 ret = -EIO;
381 goto out_buf;
382 }
383#endif
384 newblk = find_free_dqentry(dquot, &ret);
385 }
386 else
387 ret = do_insert_tree(dquot, &newblk, depth+1);
388 if (newson && ret >= 0) {
389 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
390 ret = write_blk(sb, dquot->dq_type, *treeblk, buf);
391 }
392 else if (newact && ret < 0)
393 put_free_dqblk(sb, dquot->dq_type, buf, *treeblk);
394out_buf:
395 freedqbuf(buf);
396 return ret;
397}
398
399/* Wrapper for inserting quota structure into tree */
400static inline int dq_insert_tree(struct dquot *dquot)
401{ 180{
402 int tmp = V2_DQTREEOFF; 181 return qtree_read_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot);
403 return do_insert_tree(dquot, &tmp, 0);
404} 182}
405 183
406/*
407 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
408 */
409static int v2_write_dquot(struct dquot *dquot) 184static int v2_write_dquot(struct dquot *dquot)
410{ 185{
411 int type = dquot->dq_type; 186 return qtree_write_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot);
412 ssize_t ret;
413 struct v2_disk_dqblk ddquot, empty;
414
415 /* dq_off is guarded by dqio_mutex */
416 if (!dquot->dq_off)
417 if ((ret = dq_insert_tree(dquot)) < 0) {
418 printk(KERN_ERR "VFS: Error %zd occurred while creating quota.\n", ret);
419 return ret;
420 }
421 spin_lock(&dq_data_lock);
422 mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
423 /* Argh... We may need to write structure full of zeroes but that would be
424 * treated as an empty place by the rest of the code. Format change would
425 * be definitely cleaner but the problems probably are not worth it */
426 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
427 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
428 ddquot.dqb_itime = cpu_to_le64(1);
429 spin_unlock(&dq_data_lock);
430 ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
431 (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
432 if (ret != sizeof(struct v2_disk_dqblk)) {
433 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
434 if (ret >= 0)
435 ret = -ENOSPC;
436 }
437 else
438 ret = 0;
439 dqstats.writes++;
440
441 return ret;
442} 187}
443 188
444/* Free dquot entry in data block */
445static int free_dqentry(struct dquot *dquot, uint blk)
446{
447 struct super_block *sb = dquot->dq_sb;
448 int type = dquot->dq_type;
449 struct v2_disk_dqdbheader *dh;
450 dqbuf_t buf = getdqbuf();
451 int ret = 0;
452
453 if (!buf)
454 return -ENOMEM;
455 if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
456 printk(KERN_ERR "VFS: Quota structure has offset to other "
457 "block (%u) than it should (%u).\n", blk,
458 (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
459 goto out_buf;
460 }
461 if ((ret = read_blk(sb, type, blk, buf)) < 0) {
462 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
463 goto out_buf;
464 }
465 dh = (struct v2_disk_dqdbheader *)buf;
466 le16_add_cpu(&dh->dqdh_entries, -1);
467 if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
468 if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||
469 (ret = put_free_dqblk(sb, type, buf, blk)) < 0) {
470 printk(KERN_ERR "VFS: Can't move quota data block (%u) "
471 "to free list.\n", blk);
472 goto out_buf;
473 }
474 }
475 else {
476 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
477 sizeof(struct v2_disk_dqblk));
478 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
479 /* Insert will write block itself */
480 if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
481 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
482 goto out_buf;
483 }
484 }
485 else
486 if ((ret = write_blk(sb, type, blk, buf)) < 0) {
487 printk(KERN_ERR "VFS: Can't write quota data "
488 "block %u\n", blk);
489 goto out_buf;
490 }
491 }
492 dquot->dq_off = 0; /* Quota is now unattached */
493out_buf:
494 freedqbuf(buf);
495 return ret;
496}
497
498/* Remove reference to dquot from tree */
499static int remove_tree(struct dquot *dquot, uint *blk, int depth)
500{
501 struct super_block *sb = dquot->dq_sb;
502 int type = dquot->dq_type;
503 dqbuf_t buf = getdqbuf();
504 int ret = 0;
505 uint newblk;
506 __le32 *ref = (__le32 *)buf;
507
508 if (!buf)
509 return -ENOMEM;
510 if ((ret = read_blk(sb, type, *blk, buf)) < 0) {
511 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
512 goto out_buf;
513 }
514 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
515 if (depth == V2_DQTREEDEPTH-1) {
516 ret = free_dqentry(dquot, newblk);
517 newblk = 0;
518 }
519 else
520 ret = remove_tree(dquot, &newblk, depth+1);
521 if (ret >= 0 && !newblk) {
522 int i;
523 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
524 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */
525 /* Don't put the root block into the free block list */
526 if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) {
527 put_free_dqblk(sb, type, buf, *blk);
528 *blk = 0;
529 }
530 else
531 if ((ret = write_blk(sb, type, *blk, buf)) < 0)
532 printk(KERN_ERR "VFS: Can't write quota tree "
533 "block %u.\n", *blk);
534 }
535out_buf:
536 freedqbuf(buf);
537 return ret;
538}
539
540/* Delete dquot from tree */
541static int v2_delete_dquot(struct dquot *dquot)
542{
543 uint tmp = V2_DQTREEOFF;
544
545 if (!dquot->dq_off) /* Even not allocated? */
546 return 0;
547 return remove_tree(dquot, &tmp, 0);
548}
549
550/* Find entry in block */
551static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
552{
553 dqbuf_t buf = getdqbuf();
554 loff_t ret = 0;
555 int i;
556 struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
557
558 if (!buf)
559 return -ENOMEM;
560 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
561 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
562 goto out_buf;
563 }
564 if (dquot->dq_id)
565 for (i = 0; i < V2_DQSTRINBLK &&
566 le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
567 else { /* ID 0 as a bit more complicated searching... */
568 struct v2_disk_dqblk fakedquot;
569
570 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
571 for (i = 0; i < V2_DQSTRINBLK; i++)
572 if (!le32_to_cpu(ddquot[i].dqb_id) &&
573 memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
574 break;
575 }
576 if (i == V2_DQSTRINBLK) {
577 printk(KERN_ERR "VFS: Quota for id %u referenced "
578 "but not present.\n", dquot->dq_id);
579 ret = -EIO;
580 goto out_buf;
581 }
582 else
583 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
584 v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
585out_buf:
586 freedqbuf(buf);
587 return ret;
588}
589
590/* Find entry for given id in the tree */
591static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
592{
593 dqbuf_t buf = getdqbuf();
594 loff_t ret = 0;
595 __le32 *ref = (__le32 *)buf;
596
597 if (!buf)
598 return -ENOMEM;
599 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
600 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
601 goto out_buf;
602 }
603 ret = 0;
604 blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
605 if (!blk) /* No reference? */
606 goto out_buf;
607 if (depth < V2_DQTREEDEPTH-1)
608 ret = find_tree_dqentry(dquot, blk, depth+1);
609 else
610 ret = find_block_dqentry(dquot, blk);
611out_buf:
612 freedqbuf(buf);
613 return ret;
614}
615
616/* Find entry for given id in the tree - wrapper function */
617static inline loff_t find_dqentry(struct dquot *dquot)
618{
619 return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
620}
621
622static int v2_read_dquot(struct dquot *dquot)
623{
624 int type = dquot->dq_type;
625 loff_t offset;
626 struct v2_disk_dqblk ddquot, empty;
627 int ret = 0;
628
629#ifdef __QUOTA_V2_PARANOIA
630 /* Invalidated quota? */
631 if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) {
632 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
633 return -EIO;
634 }
635#endif
636 offset = find_dqentry(dquot);
637 if (offset <= 0) { /* Entry not present? */
638 if (offset < 0)
639 printk(KERN_ERR "VFS: Can't read quota "
640 "structure for id %u.\n", dquot->dq_id);
641 dquot->dq_off = 0;
642 set_bit(DQ_FAKE_B, &dquot->dq_flags);
643 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
644 ret = offset;
645 }
646 else {
647 dquot->dq_off = offset;
648 if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
649 (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
650 != sizeof(struct v2_disk_dqblk)) {
651 if (ret >= 0)
652 ret = -EIO;
653 printk(KERN_ERR "VFS: Error while reading quota "
654 "structure for id %u.\n", dquot->dq_id);
655 memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
656 }
657 else {
658 ret = 0;
659 /* We need to escape back all-zero structure */
660 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
661 empty.dqb_itime = cpu_to_le64(1);
662 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
663 ddquot.dqb_itime = 0;
664 }
665 disk2memdqb(&dquot->dq_dqb, &ddquot);
666 if (!dquot->dq_dqb.dqb_bhardlimit &&
667 !dquot->dq_dqb.dqb_bsoftlimit &&
668 !dquot->dq_dqb.dqb_ihardlimit &&
669 !dquot->dq_dqb.dqb_isoftlimit)
670 set_bit(DQ_FAKE_B, &dquot->dq_flags);
671 }
672 dqstats.reads++;
673
674 return ret;
675}
676
677/* Check whether dquot should not be deleted. We know we are
678 * the only one operating on dquot (thanks to dq_lock) */
679static int v2_release_dquot(struct dquot *dquot) 189static int v2_release_dquot(struct dquot *dquot)
680{ 190{
681 if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) 191 return qtree_release_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot);
682 return v2_delete_dquot(dquot);
683 return 0;
684} 192}
685 193
686static struct quota_format_ops v2_format_ops = { 194static struct quota_format_ops v2_format_ops = {
diff --git a/fs/quotaio_v2.h b/fs/quotaio_v2.h
index 303d7cbe30d4..530fe580685c 100644
--- a/fs/quotaio_v2.h
+++ b/fs/quotaio_v2.h
@@ -21,6 +21,12 @@
21 0 /* GRPQUOTA */\ 21 0 /* GRPQUOTA */\
22} 22}
23 23
24/* First generic header */
25struct v2_disk_dqheader {
26 __le32 dqh_magic; /* Magic number identifying file */
27 __le32 dqh_version; /* File version */
28};
29
24/* 30/*
25 * The following structure defines the format of the disk quota file 31 * The following structure defines the format of the disk quota file
26 * (as it appears on disk) - the file is a radix tree whose leaves point 32 * (as it appears on disk) - the file is a radix tree whose leaves point
@@ -38,15 +44,6 @@ struct v2_disk_dqblk {
38 __le64 dqb_itime; /* time limit for excessive inode use */ 44 __le64 dqb_itime; /* time limit for excessive inode use */
39}; 45};
40 46
41/*
42 * Here are header structures as written on disk and their in-memory copies
43 */
44/* First generic header */
45struct v2_disk_dqheader {
46 __le32 dqh_magic; /* Magic number identifying file */
47 __le32 dqh_version; /* File version */
48};
49
50/* Header with type and version specific information */ 47/* Header with type and version specific information */
51struct v2_disk_dqinfo { 48struct v2_disk_dqinfo {
52 __le32 dqi_bgrace; /* Time before block soft limit becomes hard limit */ 49 __le32 dqi_bgrace; /* Time before block soft limit becomes hard limit */
@@ -57,23 +54,7 @@ struct v2_disk_dqinfo {
57 __le32 dqi_free_entry; /* Number of block with at least one free entry */ 54 __le32 dqi_free_entry; /* Number of block with at least one free entry */
58}; 55};
59 56
60/*
61 * Structure of header of block with quota structures. It is padded to 16 bytes so
62 * there will be space for exactly 21 quota-entries in a block
63 */
64struct v2_disk_dqdbheader {
65 __le32 dqdh_next_free; /* Number of next block with free entry */
66 __le32 dqdh_prev_free; /* Number of previous block with free entry */
67 __le16 dqdh_entries; /* Number of valid entries in block */
68 __le16 dqdh_pad1;
69 __le32 dqdh_pad2;
70};
71
72#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */ 57#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */
73#define V2_DQBLKSIZE_BITS 10 58#define V2_DQBLKSIZE_BITS 10 /* Size of leaf block in tree */
74#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */
75#define V2_DQTREEOFF 1 /* Offset of tree in file in blocks */
76#define V2_DQTREEDEPTH 4 /* Depth of quota tree */
77#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */
78 59
79#endif /* _LINUX_QUOTAIO_V2_H */ 60#endif /* _LINUX_QUOTAIO_V2_H */
diff --git a/include/linux/dqblk_qtree.h b/include/linux/dqblk_qtree.h
new file mode 100644
index 000000000000..82a16527b367
--- /dev/null
+++ b/include/linux/dqblk_qtree.h
@@ -0,0 +1,56 @@
1/*
2 * Definitions of structures and functions for quota formats using trie
3 */
4
5#ifndef _LINUX_DQBLK_QTREE_H
6#define _LINUX_DQBLK_QTREE_H
7
8#include <linux/types.h>
9
10/* Numbers of blocks needed for updates - we count with the smallest
11 * possible block size (1024) */
12#define QTREE_INIT_ALLOC 4
13#define QTREE_INIT_REWRITE 2
14#define QTREE_DEL_ALLOC 0
15#define QTREE_DEL_REWRITE 6
16
17struct dquot;
18
19/* Operations */
20struct qtree_fmt_operations {
21 void (*mem2disk_dqblk)(void *disk, struct dquot *dquot); /* Convert given entry from in memory format to disk one */
22 void (*disk2mem_dqblk)(struct dquot *dquot, void *disk); /* Convert given entry from disk format to in memory one */
23 int (*is_id)(void *disk, struct dquot *dquot); /* Is this structure for given id? */
24};
25
26/* Inmemory copy of version specific information */
27struct qtree_mem_dqinfo {
28 struct super_block *dqi_sb; /* Sb quota is on */
29 int dqi_type; /* Quota type */
30 unsigned int dqi_blocks; /* # of blocks in quota file */
31 unsigned int dqi_free_blk; /* First block in list of free blocks */
32 unsigned int dqi_free_entry; /* First block with free entry */
33 unsigned int dqi_blocksize_bits; /* Block size of quota file */
34 unsigned int dqi_entry_size; /* Size of quota entry in quota file */
35 unsigned int dqi_usable_bs; /* Space usable in block for quota data */
36 unsigned int dqi_qtree_depth; /* Precomputed depth of quota tree */
37 struct qtree_fmt_operations *dqi_ops; /* Operations for entry manipulation */
38};
39
40int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
41int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
42int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
43int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot);
44int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk);
45static inline int qtree_depth(struct qtree_mem_dqinfo *info)
46{
47 unsigned int epb = info->dqi_usable_bs >> 2;
48 unsigned long long entries = epb;
49 int i;
50
51 for (i = 1; entries < (1ULL << 32); i++)
52 entries *= epb;
53 return i;
54}
55
56#endif /* _LINUX_DQBLK_QTREE_H */
diff --git a/include/linux/dqblk_v2.h b/include/linux/dqblk_v2.h
index 4f853322cb7f..e5e22a787d58 100644
--- a/include/linux/dqblk_v2.h
+++ b/include/linux/dqblk_v2.h
@@ -1,26 +1,23 @@
1/* 1/*
2 * Definitions of structures for vfsv0 quota format 2 * Definitions for vfsv0 quota format
3 */ 3 */
4 4
5#ifndef _LINUX_DQBLK_V2_H 5#ifndef _LINUX_DQBLK_V2_H
6#define _LINUX_DQBLK_V2_H 6#define _LINUX_DQBLK_V2_H
7 7
8#include <linux/types.h> 8#include <linux/dqblk_qtree.h>
9 9
10/* id numbers of quota format */ 10/* Id number of quota format */
11#define QFMT_VFS_V0 2 11#define QFMT_VFS_V0 2
12 12
13/* Numbers of blocks needed for updates */ 13/* Numbers of blocks needed for updates */
14#define V2_INIT_ALLOC 4 14#define V2_INIT_ALLOC QTREE_INIT_ALLOC
15#define V2_INIT_REWRITE 2 15#define V2_INIT_REWRITE QTREE_INIT_REWRITE
16#define V2_DEL_ALLOC 0 16#define V2_DEL_ALLOC QTREE_DEL_ALLOC
17#define V2_DEL_REWRITE 6 17#define V2_DEL_REWRITE QTREE_DEL_REWRITE
18 18
19/* Inmemory copy of version specific information */
20struct v2_mem_dqinfo { 19struct v2_mem_dqinfo {
21 unsigned int dqi_blocks; 20 struct qtree_mem_dqinfo i;
22 unsigned int dqi_free_blk;
23 unsigned int dqi_free_entry;
24}; 21};
25 22
26#endif /* _LINUX_DQBLK_V2_H */ 23#endif /* _LINUX_DQBLK_V2_H */