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