linux/fs/quota/quota_tree.c
<<
>>
Prefs
   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
  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 */
  36static 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
  42static 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
  51static 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
  60static 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                quota_error(sb, "dquota write failed");
  69                if (ret >= 0)
  70                        ret = -EIO;
  71        }
  72        return ret;
  73}
  74
  75/* Remove empty block from list and return it */
  76static int get_free_dqblk(struct qtree_mem_dqinfo *info)
  77{
  78        char *buf = getdqbuf(info->dqi_usable_bs);
  79        struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
  80        int ret, blk;
  81
  82        if (!buf)
  83                return -ENOMEM;
  84        if (info->dqi_free_blk) {
  85                blk = info->dqi_free_blk;
  86                ret = read_blk(info, blk, buf);
  87                if (ret < 0)
  88                        goto out_buf;
  89                info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
  90        }
  91        else {
  92                memset(buf, 0, info->dqi_usable_bs);
  93                /* Assure block allocation... */
  94                ret = write_blk(info, info->dqi_blocks, buf);
  95                if (ret < 0)
  96                        goto out_buf;
  97                blk = info->dqi_blocks++;
  98        }
  99        mark_info_dirty(info->dqi_sb, info->dqi_type);
 100        ret = blk;
 101out_buf:
 102        kfree(buf);
 103        return ret;
 104}
 105
 106/* Insert empty block to the list */
 107static int put_free_dqblk(struct qtree_mem_dqinfo *info, char *buf, uint blk)
 108{
 109        struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
 110        int err;
 111
 112        dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
 113        dh->dqdh_prev_free = cpu_to_le32(0);
 114        dh->dqdh_entries = cpu_to_le16(0);
 115        err = write_blk(info, blk, buf);
 116        if (err < 0)
 117                return err;
 118        info->dqi_free_blk = blk;
 119        mark_info_dirty(info->dqi_sb, info->dqi_type);
 120        return 0;
 121}
 122
 123/* Remove given block from the list of blocks with free entries */
 124static int remove_free_dqentry(struct qtree_mem_dqinfo *info, char *buf,
 125                               uint blk)
 126{
 127        char *tmpbuf = getdqbuf(info->dqi_usable_bs);
 128        struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
 129        uint nextblk = le32_to_cpu(dh->dqdh_next_free);
 130        uint prevblk = le32_to_cpu(dh->dqdh_prev_free);
 131        int err;
 132
 133        if (!tmpbuf)
 134                return -ENOMEM;
 135        if (nextblk) {
 136                err = read_blk(info, nextblk, tmpbuf);
 137                if (err < 0)
 138                        goto out_buf;
 139                ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
 140                                                        dh->dqdh_prev_free;
 141                err = write_blk(info, nextblk, tmpbuf);
 142                if (err < 0)
 143                        goto out_buf;
 144        }
 145        if (prevblk) {
 146                err = read_blk(info, prevblk, tmpbuf);
 147                if (err < 0)
 148                        goto out_buf;
 149                ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free =
 150                                                        dh->dqdh_next_free;
 151                err = write_blk(info, prevblk, tmpbuf);
 152                if (err < 0)
 153                        goto out_buf;
 154        } else {
 155                info->dqi_free_entry = nextblk;
 156                mark_info_dirty(info->dqi_sb, info->dqi_type);
 157        }
 158        kfree(tmpbuf);
 159        dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
 160        /* No matter whether write succeeds block is out of list */
 161        if (write_blk(info, blk, buf) < 0)
 162                quota_error(info->dqi_sb, "Can't write block (%u) "
 163                            "with free entries", blk);
 164        return 0;
 165out_buf:
 166        kfree(tmpbuf);
 167        return err;
 168}
 169
 170/* Insert given block to the beginning of list with free entries */
 171static int insert_free_dqentry(struct qtree_mem_dqinfo *info, char *buf,
 172                               uint blk)
 173{
 174        char *tmpbuf = getdqbuf(info->dqi_usable_bs);
 175        struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
 176        int err;
 177
 178        if (!tmpbuf)
 179                return -ENOMEM;
 180        dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
 181        dh->dqdh_prev_free = cpu_to_le32(0);
 182        err = write_blk(info, blk, buf);
 183        if (err < 0)
 184                goto out_buf;
 185        if (info->dqi_free_entry) {
 186                err = read_blk(info, info->dqi_free_entry, tmpbuf);
 187                if (err < 0)
 188                        goto out_buf;
 189                ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
 190                                                        cpu_to_le32(blk);
 191                err = write_blk(info, info->dqi_free_entry, tmpbuf);
 192                if (err < 0)
 193                        goto out_buf;
 194        }
 195        kfree(tmpbuf);
 196        info->dqi_free_entry = blk;
 197        mark_info_dirty(info->dqi_sb, info->dqi_type);
 198        return 0;
 199out_buf:
 200        kfree(tmpbuf);
 201        return err;
 202}
 203
 204/* Is the entry in the block free? */
 205int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk)
 206{
 207        int i;
 208
 209        for (i = 0; i < info->dqi_entry_size; i++)
 210                if (disk[i])
 211                        return 0;
 212        return 1;
 213}
 214EXPORT_SYMBOL(qtree_entry_unused);
 215
 216/* Find space for dquot */
 217static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
 218                              struct dquot *dquot, int *err)
 219{
 220        uint blk, i;
 221        struct qt_disk_dqdbheader *dh;
 222        char *buf = getdqbuf(info->dqi_usable_bs);
 223        char *ddquot;
 224
 225        *err = 0;
 226        if (!buf) {
 227                *err = -ENOMEM;
 228                return 0;
 229        }
 230        dh = (struct qt_disk_dqdbheader *)buf;
 231        if (info->dqi_free_entry) {
 232                blk = info->dqi_free_entry;
 233                *err = read_blk(info, blk, buf);
 234                if (*err < 0)
 235                        goto out_buf;
 236        } else {
 237                blk = get_free_dqblk(info);
 238                if ((int)blk < 0) {
 239                        *err = blk;
 240                        kfree(buf);
 241                        return 0;
 242                }
 243                memset(buf, 0, info->dqi_usable_bs);
 244                /* This is enough as the block is already zeroed and the entry
 245                 * list is empty... */
 246                info->dqi_free_entry = blk;
 247                mark_info_dirty(dquot->dq_sb, dquot->dq_type);
 248        }
 249        /* Block will be full? */
 250        if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) {
 251                *err = remove_free_dqentry(info, buf, blk);
 252                if (*err < 0) {
 253                        quota_error(dquot->dq_sb, "Can't remove block (%u) "
 254                                    "from entry free list", blk);
 255                        goto out_buf;
 256                }
 257        }
 258        le16_add_cpu(&dh->dqdh_entries, 1);
 259        /* Find free structure in block */
 260        ddquot = buf + sizeof(struct qt_disk_dqdbheader);
 261        for (i = 0; i < qtree_dqstr_in_blk(info); i++) {
 262                if (qtree_entry_unused(info, ddquot))
 263                        break;
 264                ddquot += info->dqi_entry_size;
 265        }
 266#ifdef __QUOTA_QT_PARANOIA
 267        if (i == qtree_dqstr_in_blk(info)) {
 268                quota_error(dquot->dq_sb, "Data block full but it shouldn't");
 269                *err = -EIO;
 270                goto out_buf;
 271        }
 272#endif
 273        *err = write_blk(info, blk, buf);
 274        if (*err < 0) {
 275                quota_error(dquot->dq_sb, "Can't write quota data block %u",
 276                            blk);
 277                goto out_buf;
 278        }
 279        dquot->dq_off = (blk << info->dqi_blocksize_bits) +
 280                        sizeof(struct qt_disk_dqdbheader) +
 281                        i * info->dqi_entry_size;
 282        kfree(buf);
 283        return blk;
 284out_buf:
 285        kfree(buf);
 286        return 0;
 287}
 288
 289/* Insert reference to structure into the trie */
 290static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 291                          uint *treeblk, int depth)
 292{
 293        char *buf = getdqbuf(info->dqi_usable_bs);
 294        int ret = 0, newson = 0, newact = 0;
 295        __le32 *ref;
 296        uint newblk;
 297
 298        if (!buf)
 299                return -ENOMEM;
 300        if (!*treeblk) {
 301                ret = get_free_dqblk(info);
 302                if (ret < 0)
 303                        goto out_buf;
 304                *treeblk = ret;
 305                memset(buf, 0, info->dqi_usable_bs);
 306                newact = 1;
 307        } else {
 308                ret = read_blk(info, *treeblk, buf);
 309                if (ret < 0) {
 310                        quota_error(dquot->dq_sb, "Can't read tree quota "
 311                                    "block %u", *treeblk);
 312                        goto out_buf;
 313                }
 314        }
 315        ref = (__le32 *)buf;
 316        newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
 317        if (!newblk)
 318                newson = 1;
 319        if (depth == info->dqi_qtree_depth - 1) {
 320#ifdef __QUOTA_QT_PARANOIA
 321                if (newblk) {
 322                        quota_error(dquot->dq_sb, "Inserting already present "
 323                                    "quota entry (block %u)",
 324                                    le32_to_cpu(ref[get_index(info,
 325                                                dquot->dq_id, depth)]));
 326                        ret = -EIO;
 327                        goto out_buf;
 328                }
 329#endif
 330                newblk = find_free_dqentry(info, dquot, &ret);
 331        } else {
 332                ret = do_insert_tree(info, dquot, &newblk, depth+1);
 333        }
 334        if (newson && ret >= 0) {
 335                ref[get_index(info, dquot->dq_id, depth)] =
 336                                                        cpu_to_le32(newblk);
 337                ret = write_blk(info, *treeblk, buf);
 338        } else if (newact && ret < 0) {
 339                put_free_dqblk(info, buf, *treeblk);
 340        }
 341out_buf:
 342        kfree(buf);
 343        return ret;
 344}
 345
 346/* Wrapper for inserting quota structure into tree */
 347static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
 348                                 struct dquot *dquot)
 349{
 350        int tmp = QT_TREEOFF;
 351        return do_insert_tree(info, dquot, &tmp, 0);
 352}
 353
 354/*
 355 * We don't have to be afraid of deadlocks as we never have quotas on quota
 356 * files...
 357 */
 358int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 359{
 360        int type = dquot->dq_type;
 361        struct super_block *sb = dquot->dq_sb;
 362        ssize_t ret;
 363        char *ddquot = getdqbuf(info->dqi_entry_size);
 364
 365        if (!ddquot)
 366                return -ENOMEM;
 367
 368        /* dq_off is guarded by dqio_mutex */
 369        if (!dquot->dq_off) {
 370                ret = dq_insert_tree(info, dquot);
 371                if (ret < 0) {
 372                        quota_error(sb, "Error %zd occurred while creating "
 373                                    "quota", ret);
 374                        kfree(ddquot);
 375                        return ret;
 376                }
 377        }
 378        spin_lock(&dq_data_lock);
 379        info->dqi_ops->mem2disk_dqblk(ddquot, dquot);
 380        spin_unlock(&dq_data_lock);
 381        ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size,
 382                                    dquot->dq_off);
 383        if (ret != info->dqi_entry_size) {
 384                quota_error(sb, "dquota write failed");
 385                if (ret >= 0)
 386                        ret = -ENOSPC;
 387        } else {
 388                ret = 0;
 389        }
 390        dqstats_inc(DQST_WRITES);
 391        kfree(ddquot);
 392
 393        return ret;
 394}
 395EXPORT_SYMBOL(qtree_write_dquot);
 396
 397/* Free dquot entry in data block */
 398static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 399                        uint blk)
 400{
 401        struct qt_disk_dqdbheader *dh;
 402        char *buf = getdqbuf(info->dqi_usable_bs);
 403        int ret = 0;
 404
 405        if (!buf)
 406                return -ENOMEM;
 407        if (dquot->dq_off >> info->dqi_blocksize_bits != blk) {
 408                quota_error(dquot->dq_sb, "Quota structure has offset to "
 409                        "other block (%u) than it should (%u)", blk,
 410                        (uint)(dquot->dq_off >> info->dqi_blocksize_bits));
 411                goto out_buf;
 412        }
 413        ret = read_blk(info, blk, buf);
 414        if (ret < 0) {
 415                quota_error(dquot->dq_sb, "Can't read quota data block %u",
 416                            blk);
 417                goto out_buf;
 418        }
 419        dh = (struct qt_disk_dqdbheader *)buf;
 420        le16_add_cpu(&dh->dqdh_entries, -1);
 421        if (!le16_to_cpu(dh->dqdh_entries)) {   /* Block got free? */
 422                ret = remove_free_dqentry(info, buf, blk);
 423                if (ret >= 0)
 424                        ret = put_free_dqblk(info, buf, blk);
 425                if (ret < 0) {
 426                        quota_error(dquot->dq_sb, "Can't move quota data block "
 427                                    "(%u) to free list", blk);
 428                        goto out_buf;
 429                }
 430        } else {
 431                memset(buf +
 432                       (dquot->dq_off & ((1 << info->dqi_blocksize_bits) - 1)),
 433                       0, info->dqi_entry_size);
 434                if (le16_to_cpu(dh->dqdh_entries) ==
 435                    qtree_dqstr_in_blk(info) - 1) {
 436                        /* Insert will write block itself */
 437                        ret = insert_free_dqentry(info, buf, blk);
 438                        if (ret < 0) {
 439                                quota_error(dquot->dq_sb, "Can't insert quota "
 440                                    "data block (%u) to free entry list", blk);
 441                                goto out_buf;
 442                        }
 443                } else {
 444                        ret = write_blk(info, blk, buf);
 445                        if (ret < 0) {
 446                                quota_error(dquot->dq_sb, "Can't write quota "
 447                                            "data block %u", blk);
 448                                goto out_buf;
 449                        }
 450                }
 451        }
 452        dquot->dq_off = 0;      /* Quota is now unattached */
 453out_buf:
 454        kfree(buf);
 455        return ret;
 456}
 457
 458/* Remove reference to dquot from tree */
 459static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 460                       uint *blk, int depth)
 461{
 462        char *buf = getdqbuf(info->dqi_usable_bs);
 463        int ret = 0;
 464        uint newblk;
 465        __le32 *ref = (__le32 *)buf;
 466
 467        if (!buf)
 468                return -ENOMEM;
 469        ret = read_blk(info, *blk, buf);
 470        if (ret < 0) {
 471                quota_error(dquot->dq_sb, "Can't read quota data block %u",
 472                            *blk);
 473                goto out_buf;
 474        }
 475        newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
 476        if (depth == info->dqi_qtree_depth - 1) {
 477                ret = free_dqentry(info, dquot, newblk);
 478                newblk = 0;
 479        } else {
 480                ret = remove_tree(info, dquot, &newblk, depth+1);
 481        }
 482        if (ret >= 0 && !newblk) {
 483                int i;
 484                ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0);
 485                /* Block got empty? */
 486                for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++)
 487                        ;
 488                /* Don't put the root block into the free block list */
 489                if (i == (info->dqi_usable_bs >> 2)
 490                    && *blk != QT_TREEOFF) {
 491                        put_free_dqblk(info, buf, *blk);
 492                        *blk = 0;
 493                } else {
 494                        ret = write_blk(info, *blk, buf);
 495                        if (ret < 0)
 496                                quota_error(dquot->dq_sb,
 497                                            "Can't write quota tree block %u",
 498                                            *blk);
 499                }
 500        }
 501out_buf:
 502        kfree(buf);
 503        return ret;
 504}
 505
 506/* Delete dquot from tree */
 507int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 508{
 509        uint tmp = QT_TREEOFF;
 510
 511        if (!dquot->dq_off)     /* Even not allocated? */
 512                return 0;
 513        return remove_tree(info, dquot, &tmp, 0);
 514}
 515EXPORT_SYMBOL(qtree_delete_dquot);
 516
 517/* Find entry in block */
 518static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
 519                                 struct dquot *dquot, uint blk)
 520{
 521        char *buf = getdqbuf(info->dqi_usable_bs);
 522        loff_t ret = 0;
 523        int i;
 524        char *ddquot;
 525
 526        if (!buf)
 527                return -ENOMEM;
 528        ret = read_blk(info, blk, buf);
 529        if (ret < 0) {
 530                quota_error(dquot->dq_sb, "Can't read quota tree "
 531                            "block %u", blk);
 532                goto out_buf;
 533        }
 534        ddquot = buf + sizeof(struct qt_disk_dqdbheader);
 535        for (i = 0; i < qtree_dqstr_in_blk(info); i++) {
 536                if (info->dqi_ops->is_id(ddquot, dquot))
 537                        break;
 538                ddquot += info->dqi_entry_size;
 539        }
 540        if (i == qtree_dqstr_in_blk(info)) {
 541                quota_error(dquot->dq_sb, "Quota for id %u referenced "
 542                            "but not present", dquot->dq_id);
 543                ret = -EIO;
 544                goto out_buf;
 545        } else {
 546                ret = (blk << info->dqi_blocksize_bits) + sizeof(struct
 547                  qt_disk_dqdbheader) + i * info->dqi_entry_size;
 548        }
 549out_buf:
 550        kfree(buf);
 551        return ret;
 552}
 553
 554/* Find entry for given id in the tree */
 555static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
 556                                struct dquot *dquot, uint blk, int depth)
 557{
 558        char *buf = getdqbuf(info->dqi_usable_bs);
 559        loff_t ret = 0;
 560        __le32 *ref = (__le32 *)buf;
 561
 562        if (!buf)
 563                return -ENOMEM;
 564        ret = read_blk(info, blk, buf);
 565        if (ret < 0) {
 566                quota_error(dquot->dq_sb, "Can't read quota tree block %u",
 567                            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);
 578out_buf:
 579        kfree(buf);
 580        return ret;
 581}
 582
 583/* Find entry for given id in the tree - wrapper function */
 584static 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
 590int 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                quota_error(sb, "Quota invalidated while reading!");
 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                                quota_error(sb, "Can't read quota structure "
 611                                            "for id %u", 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                quota_error(sb, "Error while reading quota structure for id %u",
 629                            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);
 644out:
 645        dqstats_inc(DQST_READS);
 646        return ret;
 647}
 648EXPORT_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) */
 652int 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}
 659EXPORT_SYMBOL(qtree_release_dquot);
 660
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.