quota: Remove superfluous inlines
[linux-block.git] / fs / quota / quota_tree.c
CommitLineData
1ccd14b9
JK
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
1ccd14b9
JK
25static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
26{
27 unsigned int epb = info->dqi_usable_bs >> 2;
28
29 depth = info->dqi_qtree_depth - depth - 1;
30 while (depth--)
31 id /= epb;
32 return id % epb;
33}
34
35/* Number of entries in one blocks */
7a2435d8 36static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info)
1ccd14b9
JK
37{
38 return (info->dqi_usable_bs - sizeof(struct qt_disk_dqdbheader))
39 / info->dqi_entry_size;
40}
41
d26ac1a8 42static char *getdqbuf(size_t size)
1ccd14b9 43{
d26ac1a8 44 char *buf = kmalloc(size, GFP_NOFS);
1ccd14b9
JK
45 if (!buf)
46 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
47 return buf;
48}
49
7a2435d8 50static ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf)
1ccd14b9
JK
51{
52 struct super_block *sb = info->dqi_sb;
53
54 memset(buf, 0, info->dqi_usable_bs);
d26ac1a8 55 return sb->s_op->quota_read(sb, info->dqi_type, buf,
1ccd14b9
JK
56 info->dqi_usable_bs, blk << info->dqi_blocksize_bits);
57}
58
7a2435d8 59static ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf)
1ccd14b9
JK
60{
61 struct super_block *sb = info->dqi_sb;
62
d26ac1a8 63 return sb->s_op->quota_write(sb, info->dqi_type, buf,
1ccd14b9
JK
64 info->dqi_usable_bs, blk << info->dqi_blocksize_bits);
65}
66
67/* Remove empty block from list and return it */
68static int get_free_dqblk(struct qtree_mem_dqinfo *info)
69{
d26ac1a8 70 char *buf = getdqbuf(info->dqi_usable_bs);
1ccd14b9
JK
71 struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
72 int ret, blk;
73
74 if (!buf)
75 return -ENOMEM;
76 if (info->dqi_free_blk) {
77 blk = info->dqi_free_blk;
78 ret = read_blk(info, blk, buf);
79 if (ret < 0)
80 goto out_buf;
81 info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
82 }
83 else {
84 memset(buf, 0, info->dqi_usable_bs);
85 /* Assure block allocation... */
86 ret = write_blk(info, info->dqi_blocks, buf);
87 if (ret < 0)
88 goto out_buf;
89 blk = info->dqi_blocks++;
90 }
91 mark_info_dirty(info->dqi_sb, info->dqi_type);
92 ret = blk;
93out_buf:
d26ac1a8 94 kfree(buf);
1ccd14b9
JK
95 return ret;
96}
97
98/* Insert empty block to the list */
d26ac1a8 99static int put_free_dqblk(struct qtree_mem_dqinfo *info, char *buf, uint blk)
1ccd14b9
JK
100{
101 struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
102 int err;
103
104 dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
105 dh->dqdh_prev_free = cpu_to_le32(0);
106 dh->dqdh_entries = cpu_to_le16(0);
107 err = write_blk(info, blk, buf);
108 if (err < 0)
109 return err;
110 info->dqi_free_blk = blk;
111 mark_info_dirty(info->dqi_sb, info->dqi_type);
112 return 0;
113}
114
115/* Remove given block from the list of blocks with free entries */
d26ac1a8 116static int remove_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, uint blk)
1ccd14b9 117{
d26ac1a8 118 char *tmpbuf = getdqbuf(info->dqi_usable_bs);
1ccd14b9
JK
119 struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
120 uint nextblk = le32_to_cpu(dh->dqdh_next_free);
121 uint prevblk = le32_to_cpu(dh->dqdh_prev_free);
122 int err;
123
124 if (!tmpbuf)
125 return -ENOMEM;
126 if (nextblk) {
127 err = read_blk(info, nextblk, tmpbuf);
128 if (err < 0)
129 goto out_buf;
130 ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
131 dh->dqdh_prev_free;
132 err = write_blk(info, nextblk, tmpbuf);
133 if (err < 0)
134 goto out_buf;
135 }
136 if (prevblk) {
137 err = read_blk(info, prevblk, tmpbuf);
138 if (err < 0)
139 goto out_buf;
140 ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free =
141 dh->dqdh_next_free;
142 err = write_blk(info, prevblk, tmpbuf);
143 if (err < 0)
144 goto out_buf;
145 } else {
146 info->dqi_free_entry = nextblk;
147 mark_info_dirty(info->dqi_sb, info->dqi_type);
148 }
d26ac1a8 149 kfree(tmpbuf);
1ccd14b9
JK
150 dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
151 /* No matter whether write succeeds block is out of list */
152 if (write_blk(info, blk, buf) < 0)
153 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
154 return 0;
155out_buf:
d26ac1a8 156 kfree(tmpbuf);
1ccd14b9
JK
157 return err;
158}
159
160/* Insert given block to the beginning of list with free entries */
d26ac1a8 161static int insert_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, uint blk)
1ccd14b9 162{
d26ac1a8 163 char *tmpbuf = getdqbuf(info->dqi_usable_bs);
1ccd14b9
JK
164 struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
165 int err;
166
167 if (!tmpbuf)
168 return -ENOMEM;
169 dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
170 dh->dqdh_prev_free = cpu_to_le32(0);
171 err = write_blk(info, blk, buf);
172 if (err < 0)
173 goto out_buf;
174 if (info->dqi_free_entry) {
175 err = read_blk(info, info->dqi_free_entry, tmpbuf);
176 if (err < 0)
177 goto out_buf;
178 ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
179 cpu_to_le32(blk);
180 err = write_blk(info, info->dqi_free_entry, tmpbuf);
181 if (err < 0)
182 goto out_buf;
183 }
d26ac1a8 184 kfree(tmpbuf);
1ccd14b9
JK
185 info->dqi_free_entry = blk;
186 mark_info_dirty(info->dqi_sb, info->dqi_type);
187 return 0;
188out_buf:
d26ac1a8 189 kfree(tmpbuf);
1ccd14b9
JK
190 return err;
191}
192
193/* Is the entry in the block free? */
194int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk)
195{
196 int i;
197
198 for (i = 0; i < info->dqi_entry_size; i++)
199 if (disk[i])
200 return 0;
201 return 1;
202}
203EXPORT_SYMBOL(qtree_entry_unused);
204
205/* Find space for dquot */
206static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
207 struct dquot *dquot, int *err)
208{
209 uint blk, i;
210 struct qt_disk_dqdbheader *dh;
d26ac1a8 211 char *buf = getdqbuf(info->dqi_usable_bs);
1ccd14b9
JK
212 char *ddquot;
213
214 *err = 0;
215 if (!buf) {
216 *err = -ENOMEM;
217 return 0;
218 }
219 dh = (struct qt_disk_dqdbheader *)buf;
220 if (info->dqi_free_entry) {
221 blk = info->dqi_free_entry;
222 *err = read_blk(info, blk, buf);
223 if (*err < 0)
224 goto out_buf;
225 } else {
226 blk = get_free_dqblk(info);
227 if ((int)blk < 0) {
228 *err = blk;
d26ac1a8 229 kfree(buf);
1ccd14b9
JK
230 return 0;
231 }
232 memset(buf, 0, info->dqi_usable_bs);
233 /* This is enough as block is already zeroed and entry list is empty... */
234 info->dqi_free_entry = blk;
235 mark_info_dirty(dquot->dq_sb, dquot->dq_type);
236 }
237 /* Block will be full? */
238 if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) {
239 *err = remove_free_dqentry(info, buf, blk);
240 if (*err < 0) {
241 printk(KERN_ERR "VFS: find_free_dqentry(): Can't "
242 "remove block (%u) from entry free list.\n",
243 blk);
244 goto out_buf;
245 }
246 }
247 le16_add_cpu(&dh->dqdh_entries, 1);
248 /* Find free structure in block */
d26ac1a8 249 for (i = 0, ddquot = buf + sizeof(struct qt_disk_dqdbheader);
1ccd14b9 250 i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot);
d26ac1a8
JK
251 i++, ddquot += info->dqi_entry_size)
252 ;
1ccd14b9
JK
253#ifdef __QUOTA_QT_PARANOIA
254 if (i == qtree_dqstr_in_blk(info)) {
255 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full "
256 "but it shouldn't.\n");
257 *err = -EIO;
258 goto out_buf;
259 }
260#endif
261 *err = write_blk(info, blk, buf);
262 if (*err < 0) {
263 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota "
264 "data block %u.\n", blk);
265 goto out_buf;
266 }
267 dquot->dq_off = (blk << info->dqi_blocksize_bits) +
268 sizeof(struct qt_disk_dqdbheader) +
269 i * info->dqi_entry_size;
d26ac1a8 270 kfree(buf);
1ccd14b9
JK
271 return blk;
272out_buf:
d26ac1a8 273 kfree(buf);
1ccd14b9
JK
274 return 0;
275}
276
277/* Insert reference to structure into the trie */
278static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
279 uint *treeblk, int depth)
280{
d26ac1a8 281 char *buf = getdqbuf(info->dqi_usable_bs);
1ccd14b9
JK
282 int ret = 0, newson = 0, newact = 0;
283 __le32 *ref;
284 uint newblk;
285
286 if (!buf)
287 return -ENOMEM;
288 if (!*treeblk) {
289 ret = get_free_dqblk(info);
290 if (ret < 0)
291 goto out_buf;
292 *treeblk = ret;
293 memset(buf, 0, info->dqi_usable_bs);
294 newact = 1;
295 } else {
296 ret = read_blk(info, *treeblk, buf);
297 if (ret < 0) {
298 printk(KERN_ERR "VFS: Can't read tree quota block "
299 "%u.\n", *treeblk);
300 goto out_buf;
301 }
302 }
303 ref = (__le32 *)buf;
304 newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
305 if (!newblk)
306 newson = 1;
307 if (depth == info->dqi_qtree_depth - 1) {
308#ifdef __QUOTA_QT_PARANOIA
309 if (newblk) {
310 printk(KERN_ERR "VFS: Inserting already present quota "
311 "entry (block %u).\n",
312 le32_to_cpu(ref[get_index(info,
313 dquot->dq_id, depth)]));
314 ret = -EIO;
315 goto out_buf;
316 }
317#endif
318 newblk = find_free_dqentry(info, dquot, &ret);
319 } else {
320 ret = do_insert_tree(info, dquot, &newblk, depth+1);
321 }
322 if (newson && ret >= 0) {
323 ref[get_index(info, dquot->dq_id, depth)] =
324 cpu_to_le32(newblk);
325 ret = write_blk(info, *treeblk, buf);
326 } else if (newact && ret < 0) {
327 put_free_dqblk(info, buf, *treeblk);
328 }
329out_buf:
d26ac1a8 330 kfree(buf);
1ccd14b9
JK
331 return ret;
332}
333
334/* Wrapper for inserting quota structure into tree */
335static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
336 struct dquot *dquot)
337{
338 int tmp = QT_TREEOFF;
339 return do_insert_tree(info, dquot, &tmp, 0);
340}
341
342/*
343 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
344 */
345int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
346{
347 int type = dquot->dq_type;
348 struct super_block *sb = dquot->dq_sb;
349 ssize_t ret;
d26ac1a8 350 char *ddquot = getdqbuf(info->dqi_entry_size);
1ccd14b9
JK
351
352 if (!ddquot)
353 return -ENOMEM;
354
355 /* dq_off is guarded by dqio_mutex */
356 if (!dquot->dq_off) {
357 ret = dq_insert_tree(info, dquot);
358 if (ret < 0) {
359 printk(KERN_ERR "VFS: Error %zd occurred while "
360 "creating quota.\n", ret);
d26ac1a8 361 kfree(ddquot);
1ccd14b9
JK
362 return ret;
363 }
364 }
365 spin_lock(&dq_data_lock);
366 info->dqi_ops->mem2disk_dqblk(ddquot, dquot);
367 spin_unlock(&dq_data_lock);
d26ac1a8
JK
368 ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size,
369 dquot->dq_off);
1ccd14b9
JK
370 if (ret != info->dqi_entry_size) {
371 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
372 sb->s_id);
373 if (ret >= 0)
374 ret = -ENOSPC;
375 } else {
376 ret = 0;
377 }
378 dqstats.writes++;
d26ac1a8 379 kfree(ddquot);
1ccd14b9
JK
380
381 return ret;
382}
383EXPORT_SYMBOL(qtree_write_dquot);
384
385/* Free dquot entry in data block */
386static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
387 uint blk)
388{
389 struct qt_disk_dqdbheader *dh;
d26ac1a8 390 char *buf = getdqbuf(info->dqi_usable_bs);
1ccd14b9
JK
391 int ret = 0;
392
393 if (!buf)
394 return -ENOMEM;
395 if (dquot->dq_off >> info->dqi_blocksize_bits != blk) {
396 printk(KERN_ERR "VFS: Quota structure has offset to other "
397 "block (%u) than it should (%u).\n", blk,
398 (uint)(dquot->dq_off >> info->dqi_blocksize_bits));
399 goto out_buf;
400 }
401 ret = read_blk(info, blk, buf);
402 if (ret < 0) {
403 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
404 goto out_buf;
405 }
406 dh = (struct qt_disk_dqdbheader *)buf;
407 le16_add_cpu(&dh->dqdh_entries, -1);
408 if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
409 ret = remove_free_dqentry(info, buf, blk);
410 if (ret >= 0)
411 ret = put_free_dqblk(info, buf, blk);
412 if (ret < 0) {
413 printk(KERN_ERR "VFS: Can't move quota data block (%u) "
414 "to free list.\n", blk);
415 goto out_buf;
416 }
417 } else {
418 memset(buf +
419 (dquot->dq_off & ((1 << info->dqi_blocksize_bits) - 1)),
420 0, info->dqi_entry_size);
421 if (le16_to_cpu(dh->dqdh_entries) ==
422 qtree_dqstr_in_blk(info) - 1) {
423 /* Insert will write block itself */
424 ret = insert_free_dqentry(info, buf, blk);
425 if (ret < 0) {
426 printk(KERN_ERR "VFS: Can't insert quota data "
427 "block (%u) to free entry list.\n", blk);
428 goto out_buf;
429 }
430 } else {
431 ret = write_blk(info, blk, buf);
432 if (ret < 0) {
433 printk(KERN_ERR "VFS: Can't write quota data "
434 "block %u\n", blk);
435 goto out_buf;
436 }
437 }
438 }
439 dquot->dq_off = 0; /* Quota is now unattached */
440out_buf:
d26ac1a8 441 kfree(buf);
1ccd14b9
JK
442 return ret;
443}
444
445/* Remove reference to dquot from tree */
446static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
447 uint *blk, int depth)
448{
d26ac1a8 449 char *buf = getdqbuf(info->dqi_usable_bs);
1ccd14b9
JK
450 int ret = 0;
451 uint newblk;
452 __le32 *ref = (__le32 *)buf;
453
454 if (!buf)
455 return -ENOMEM;
456 ret = read_blk(info, *blk, buf);
457 if (ret < 0) {
458 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
459 goto out_buf;
460 }
461 newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
462 if (depth == info->dqi_qtree_depth - 1) {
463 ret = free_dqentry(info, dquot, newblk);
464 newblk = 0;
465 } else {
466 ret = remove_tree(info, dquot, &newblk, depth+1);
467 }
468 if (ret >= 0 && !newblk) {
469 int i;
470 ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0);
471 /* Block got empty? */
d26ac1a8
JK
472 for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++)
473 ;
1ccd14b9
JK
474 /* Don't put the root block into the free block list */
475 if (i == (info->dqi_usable_bs >> 2)
476 && *blk != QT_TREEOFF) {
477 put_free_dqblk(info, buf, *blk);
478 *blk = 0;
479 } else {
480 ret = write_blk(info, *blk, buf);
481 if (ret < 0)
482 printk(KERN_ERR "VFS: Can't write quota tree "
483 "block %u.\n", *blk);
484 }
485 }
486out_buf:
d26ac1a8 487 kfree(buf);
1ccd14b9
JK
488 return ret;
489}
490
491/* Delete dquot from tree */
492int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
493{
494 uint tmp = QT_TREEOFF;
495
496 if (!dquot->dq_off) /* Even not allocated? */
497 return 0;
498 return remove_tree(info, dquot, &tmp, 0);
499}
500EXPORT_SYMBOL(qtree_delete_dquot);
501
502/* Find entry in block */
503static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
504 struct dquot *dquot, uint blk)
505{
d26ac1a8 506 char *buf = getdqbuf(info->dqi_usable_bs);
1ccd14b9
JK
507 loff_t ret = 0;
508 int i;
509 char *ddquot;
510
511 if (!buf)
512 return -ENOMEM;
513 ret = read_blk(info, blk, buf);
514 if (ret < 0) {
515 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
516 goto out_buf;
517 }
d26ac1a8 518 for (i = 0, ddquot = buf + sizeof(struct qt_disk_dqdbheader);
1ccd14b9 519 i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot);
d26ac1a8
JK
520 i++, ddquot += info->dqi_entry_size)
521 ;
1ccd14b9
JK
522 if (i == qtree_dqstr_in_blk(info)) {
523 printk(KERN_ERR "VFS: Quota for id %u referenced "
524 "but not present.\n", dquot->dq_id);
525 ret = -EIO;
526 goto out_buf;
527 } else {
528 ret = (blk << info->dqi_blocksize_bits) + sizeof(struct
529 qt_disk_dqdbheader) + i * info->dqi_entry_size;
530 }
531out_buf:
d26ac1a8 532 kfree(buf);
1ccd14b9
JK
533 return ret;
534}
535
536/* Find entry for given id in the tree */
537static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
538 struct dquot *dquot, uint blk, int depth)
539{
d26ac1a8 540 char *buf = getdqbuf(info->dqi_usable_bs);
1ccd14b9
JK
541 loff_t ret = 0;
542 __le32 *ref = (__le32 *)buf;
543
544 if (!buf)
545 return -ENOMEM;
546 ret = read_blk(info, blk, buf);
547 if (ret < 0) {
548 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
549 goto out_buf;
550 }
551 ret = 0;
552 blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
553 if (!blk) /* No reference? */
554 goto out_buf;
555 if (depth < info->dqi_qtree_depth - 1)
556 ret = find_tree_dqentry(info, dquot, blk, depth+1);
557 else
558 ret = find_block_dqentry(info, dquot, blk);
559out_buf:
d26ac1a8 560 kfree(buf);
1ccd14b9
JK
561 return ret;
562}
563
564/* Find entry for given id in the tree - wrapper function */
565static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info,
566 struct dquot *dquot)
567{
568 return find_tree_dqentry(info, dquot, QT_TREEOFF, 0);
569}
570
571int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
572{
573 int type = dquot->dq_type;
574 struct super_block *sb = dquot->dq_sb;
575 loff_t offset;
d26ac1a8 576 char *ddquot;
1ccd14b9
JK
577 int ret = 0;
578
579#ifdef __QUOTA_QT_PARANOIA
580 /* Invalidated quota? */
581 if (!sb_dqopt(dquot->dq_sb)->files[type]) {
582 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
583 return -EIO;
584 }
585#endif
586 /* Do we know offset of the dquot entry in the quota file? */
587 if (!dquot->dq_off) {
588 offset = find_dqentry(info, dquot);
589 if (offset <= 0) { /* Entry not present? */
590 if (offset < 0)
591 printk(KERN_ERR "VFS: Can't read quota "
592 "structure for id %u.\n", dquot->dq_id);
593 dquot->dq_off = 0;
594 set_bit(DQ_FAKE_B, &dquot->dq_flags);
595 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
596 ret = offset;
597 goto out;
598 }
599 dquot->dq_off = offset;
600 }
601 ddquot = getdqbuf(info->dqi_entry_size);
602 if (!ddquot)
603 return -ENOMEM;
d26ac1a8
JK
604 ret = sb->s_op->quota_read(sb, type, ddquot, info->dqi_entry_size,
605 dquot->dq_off);
1ccd14b9
JK
606 if (ret != info->dqi_entry_size) {
607 if (ret >= 0)
608 ret = -EIO;
609 printk(KERN_ERR "VFS: Error while reading quota "
610 "structure for id %u.\n", dquot->dq_id);
611 set_bit(DQ_FAKE_B, &dquot->dq_flags);
612 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
d26ac1a8 613 kfree(ddquot);
1ccd14b9
JK
614 goto out;
615 }
616 spin_lock(&dq_data_lock);
617 info->dqi_ops->disk2mem_dqblk(dquot, ddquot);
618 if (!dquot->dq_dqb.dqb_bhardlimit &&
619 !dquot->dq_dqb.dqb_bsoftlimit &&
620 !dquot->dq_dqb.dqb_ihardlimit &&
621 !dquot->dq_dqb.dqb_isoftlimit)
622 set_bit(DQ_FAKE_B, &dquot->dq_flags);
623 spin_unlock(&dq_data_lock);
d26ac1a8 624 kfree(ddquot);
1ccd14b9
JK
625out:
626 dqstats.reads++;
627 return ret;
628}
629EXPORT_SYMBOL(qtree_read_dquot);
630
631/* Check whether dquot should not be deleted. We know we are
632 * the only one operating on dquot (thanks to dq_lock) */
633int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
634{
635 if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
636 return qtree_delete_dquot(info, dquot);
637 return 0;
638}
639EXPORT_SYMBOL(qtree_release_dquot);