diff options
author | Jan Kara <jack@suse.cz> | 2016-01-25 14:39:27 -0500 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2016-02-09 07:05:23 -0500 |
commit | 0066373d9f9320f69f24b080ee00d10f14397355 (patch) | |
tree | 6f52ae0d0b524e2bfa79abbe3676771523cb63b2 | |
parent | be6257b251cebd2deb8c76d43e387e28e3f7412d (diff) |
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>
-rw-r--r-- | fs/quota/quota_tree.c | 67 | ||||
-rw-r--r-- | fs/quota/quota_v2.c | 6 | ||||
-rw-r--r-- | include/linux/dqblk_qtree.h | 2 |
3 files changed, 73 insertions, 2 deletions
diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c index 58efb83dec1c..0738972e8d3f 100644 --- a/fs/quota/quota_tree.c +++ b/fs/quota/quota_tree.c | |||
@@ -22,10 +22,9 @@ MODULE_LICENSE("GPL"); | |||
22 | 22 | ||
23 | #define __QUOTA_QT_PARANOIA | 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 | unsigned int epb = info->dqi_usable_bs >> 2; | 27 | unsigned int epb = info->dqi_usable_bs >> 2; |
28 | qid_t id = from_kqid(&init_user_ns, qid); | ||
29 | 28 | ||
30 | depth = info->dqi_qtree_depth - depth - 1; | 29 | depth = info->dqi_qtree_depth - depth - 1; |
31 | while (depth--) | 30 | while (depth--) |
@@ -33,6 +32,13 @@ static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) | |||
33 | return id % epb; | 32 | return id % epb; |
34 | } | 33 | } |
35 | 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); | ||
40 | } | ||
41 | |||
36 | /* Number of entries in one blocks */ | 42 | /* Number of entries in one blocks */ |
37 | static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) | 43 | static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) |
38 | { | 44 | { |
@@ -668,3 +674,60 @@ int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) | |||
668 | return 0; | 674 | return 0; |
669 | } | 675 | } |
670 | EXPORT_SYMBOL(qtree_release_dquot); | 676 | EXPORT_SYMBOL(qtree_release_dquot); |
677 | |||
678 | static int find_next_id(struct qtree_mem_dqinfo *info, qid_t *id, | ||
679 | unsigned int blk, int depth) | ||
680 | { | ||
681 | char *buf = getdqbuf(info->dqi_usable_bs); | ||
682 | __le32 *ref = (__le32 *)buf; | ||
683 | ssize_t ret; | ||
684 | unsigned int epb = info->dqi_usable_bs >> 2; | ||
685 | unsigned int level_inc = 1; | ||
686 | int i; | ||
687 | |||
688 | if (!buf) | ||
689 | return -ENOMEM; | ||
690 | |||
691 | for (i = depth; i < info->dqi_qtree_depth - 1; i++) | ||
692 | level_inc *= epb; | ||
693 | |||
694 | ret = read_blk(info, blk, buf); | ||
695 | if (ret < 0) { | ||
696 | quota_error(info->dqi_sb, | ||
697 | "Can't read quota tree block %u", blk); | ||
698 | goto out_buf; | ||
699 | } | ||
700 | for (i = __get_index(info, *id, depth); i < epb; i++) { | ||
701 | if (ref[i] == cpu_to_le32(0)) { | ||
702 | *id += level_inc; | ||
703 | continue; | ||
704 | } | ||
705 | if (depth == info->dqi_qtree_depth - 1) { | ||
706 | ret = 0; | ||
707 | goto out_buf; | ||
708 | } | ||
709 | ret = find_next_id(info, id, le32_to_cpu(ref[i]), depth + 1); | ||
710 | if (ret != -ENOENT) | ||
711 | break; | ||
712 | } | ||
713 | if (i == epb) { | ||
714 | ret = -ENOENT; | ||
715 | goto out_buf; | ||
716 | } | ||
717 | out_buf: | ||
718 | kfree(buf); | ||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid) | ||
723 | { | ||
724 | qid_t id = from_kqid(&init_user_ns, *qid); | ||
725 | int ret; | ||
726 | |||
727 | ret = find_next_id(info, &id, QT_TREEOFF, 0); | ||
728 | if (ret < 0) | ||
729 | return ret; | ||
730 | *qid = make_kqid(&init_user_ns, qid->type, id); | ||
731 | return 0; | ||
732 | } | ||
733 | EXPORT_SYMBOL(qtree_get_next_id); | ||
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index ed85d4f35c04..ca71bf881ad1 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c | |||
@@ -304,6 +304,11 @@ static int v2_free_file_info(struct super_block *sb, int type) | |||
304 | return 0; | 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 | static const struct quota_format_ops v2_format_ops = { | 312 | static const struct quota_format_ops v2_format_ops = { |
308 | .check_quota_file = v2_check_quota_file, | 313 | .check_quota_file = v2_check_quota_file, |
309 | .read_file_info = v2_read_file_info, | 314 | .read_file_info = v2_read_file_info, |
@@ -312,6 +317,7 @@ static const struct quota_format_ops v2_format_ops = { | |||
312 | .read_dqblk = v2_read_dquot, | 317 | .read_dqblk = v2_read_dquot, |
313 | .commit_dqblk = v2_write_dquot, | 318 | .commit_dqblk = v2_write_dquot, |
314 | .release_dqblk = v2_release_dquot, | 319 | .release_dqblk = v2_release_dquot, |
320 | .get_next_id = v2_get_next_id, | ||
315 | }; | 321 | }; |
316 | 322 | ||
317 | static struct quota_format_type v2r0_quota_format = { | 323 | static struct quota_format_type v2r0_quota_format = { |
diff --git a/include/linux/dqblk_qtree.h b/include/linux/dqblk_qtree.h index ff8b55359648..0de21e935976 100644 --- a/include/linux/dqblk_qtree.h +++ b/include/linux/dqblk_qtree.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #define QTREE_DEL_REWRITE 6 | 15 | #define QTREE_DEL_REWRITE 6 |
16 | 16 | ||
17 | struct dquot; | 17 | struct dquot; |
18 | struct kqid; | ||
18 | 19 | ||
19 | /* Operations */ | 20 | /* Operations */ |
20 | struct qtree_fmt_operations { | 21 | struct qtree_fmt_operations { |
@@ -52,5 +53,6 @@ static inline int qtree_depth(struct qtree_mem_dqinfo *info) | |||
52 | entries *= epb; | 53 | entries *= epb; |
53 | return i; | 54 | return i; |
54 | } | 55 | } |
56 | int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid); | ||
55 | 57 | ||
56 | #endif /* _LINUX_DQBLK_QTREE_H */ | 58 | #endif /* _LINUX_DQBLK_QTREE_H */ |