Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

quota_v2: Implement get_next_id() for V2 quota format

Implement functions to get id of next existing quota structure in quota
file for quota tree based formats and thus for V2 quota format.

Signed-off-by: Jan Kara <jack@suse.cz>

Jan Kara 0066373d be6257b2

+73 -2
+65 -2
fs/quota/quota_tree.c
··· 22 22 23 23 #define __QUOTA_QT_PARANOIA 24 24 25 - static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) 25 + static int __get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth) 26 26 { 27 27 unsigned int epb = info->dqi_usable_bs >> 2; 28 - qid_t id = from_kqid(&init_user_ns, qid); 29 28 30 29 depth = info->dqi_qtree_depth - depth - 1; 31 30 while (depth--) 32 31 id /= epb; 33 32 return id % epb; 33 + } 34 + 35 + static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) 36 + { 37 + qid_t id = from_kqid(&init_user_ns, qid); 38 + 39 + return __get_index(info, id, depth); 34 40 } 35 41 36 42 /* Number of entries in one blocks */ ··· 674 668 return 0; 675 669 } 676 670 EXPORT_SYMBOL(qtree_release_dquot); 671 + 672 + static int find_next_id(struct qtree_mem_dqinfo *info, qid_t *id, 673 + unsigned int blk, int depth) 674 + { 675 + char *buf = getdqbuf(info->dqi_usable_bs); 676 + __le32 *ref = (__le32 *)buf; 677 + ssize_t ret; 678 + unsigned int epb = info->dqi_usable_bs >> 2; 679 + unsigned int level_inc = 1; 680 + int i; 681 + 682 + if (!buf) 683 + return -ENOMEM; 684 + 685 + for (i = depth; i < info->dqi_qtree_depth - 1; i++) 686 + level_inc *= epb; 687 + 688 + ret = read_blk(info, blk, buf); 689 + if (ret < 0) { 690 + quota_error(info->dqi_sb, 691 + "Can't read quota tree block %u", blk); 692 + goto out_buf; 693 + } 694 + for (i = __get_index(info, *id, depth); i < epb; i++) { 695 + if (ref[i] == cpu_to_le32(0)) { 696 + *id += level_inc; 697 + continue; 698 + } 699 + if (depth == info->dqi_qtree_depth - 1) { 700 + ret = 0; 701 + goto out_buf; 702 + } 703 + ret = find_next_id(info, id, le32_to_cpu(ref[i]), depth + 1); 704 + if (ret != -ENOENT) 705 + break; 706 + } 707 + if (i == epb) { 708 + ret = -ENOENT; 709 + goto out_buf; 710 + } 711 + out_buf: 712 + kfree(buf); 713 + return ret; 714 + } 715 + 716 + int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid) 717 + { 718 + qid_t id = from_kqid(&init_user_ns, *qid); 719 + int ret; 720 + 721 + ret = find_next_id(info, &id, QT_TREEOFF, 0); 722 + if (ret < 0) 723 + return ret; 724 + *qid = make_kqid(&init_user_ns, qid->type, id); 725 + return 0; 726 + } 727 + EXPORT_SYMBOL(qtree_get_next_id);
+6
fs/quota/quota_v2.c
··· 304 304 return 0; 305 305 } 306 306 307 + static int v2_get_next_id(struct super_block *sb, struct kqid *qid) 308 + { 309 + return qtree_get_next_id(sb_dqinfo(sb, qid->type)->dqi_priv, qid); 310 + } 311 + 307 312 static const struct quota_format_ops v2_format_ops = { 308 313 .check_quota_file = v2_check_quota_file, 309 314 .read_file_info = v2_read_file_info, ··· 317 312 .read_dqblk = v2_read_dquot, 318 313 .commit_dqblk = v2_write_dquot, 319 314 .release_dqblk = v2_release_dquot, 315 + .get_next_id = v2_get_next_id, 320 316 }; 321 317 322 318 static struct quota_format_type v2r0_quota_format = {
+2
include/linux/dqblk_qtree.h
··· 15 15 #define QTREE_DEL_REWRITE 6 16 16 17 17 struct dquot; 18 + struct kqid; 18 19 19 20 /* Operations */ 20 21 struct qtree_fmt_operations { ··· 53 52 entries *= epb; 54 53 return i; 55 54 } 55 + int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid); 56 56 57 57 #endif /* _LINUX_DQBLK_QTREE_H */