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 typedef char *dqbuf_t; 26 27 static 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 */ 38 static 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 44 static 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 52 static inline void freedqbuf(dqbuf_t buf) 53 { 54 kfree(buf); 55 } 56 57 static 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 66 static 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 */ 75 static 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; 100 out_buf: 101 freedqbuf(buf); 102 return ret; 103 } 104 105 /* Insert empty block to the list */ 106 static 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 */ 123 static 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; 162 out_buf: 163 freedqbuf(tmpbuf); 164 return err; 165 } 166 167 /* Insert given block to the beginning of list with free entries */ 168 static 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; 195 out_buf: 196 freedqbuf(tmpbuf); 197 return err; 198 } 199 200 /* Is the entry in the block free? */ 201 int 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 } 210 EXPORT_SYMBOL(qtree_entry_unused); 211 212 /* Find space for dquot */ 213 static 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; 278 out_buf: 279 freedqbuf(buf); 280 return 0; 281 } 282 283 /* Insert reference to structure into the trie */ 284 static 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 } 335 out_buf: 336 freedqbuf(buf); 337 return ret; 338 } 339 340 /* Wrapper for inserting quota structure into tree */ 341 static 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 */ 351 int 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 } 389 EXPORT_SYMBOL(qtree_write_dquot); 390 391 /* Free dquot entry in data block */ 392 static 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 */ 446 out_buf: 447 freedqbuf(buf); 448 return ret; 449 } 450 451 /* Remove reference to dquot from tree */ 452 static 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 } 493 out_buf: 494 freedqbuf(buf); 495 return ret; 496 } 497 498 /* Delete dquot from tree */ 499 int 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 } 507 EXPORT_SYMBOL(qtree_delete_dquot); 508 509 /* Find entry in block */ 510 static 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 } 537 out_buf: 538 freedqbuf(buf); 539 return ret; 540 } 541 542 /* Find entry for given id in the tree */ 543 static 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); 565 out_buf: 566 freedqbuf(buf); 567 return ret; 568 } 569 570 /* Find entry for given id in the tree - wrapper function */ 571 static 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 577 int 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); 631 out: 632 dqstats.reads++; 633 return ret; 634 } 635 EXPORT_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) */ 639 int 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 } 645 EXPORT_SYMBOL(qtree_release_dquot); 646