aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2016-01-25 14:39:27 -0500
committerJan Kara <jack@suse.cz>2016-02-09 07:05:23 -0500
commit0066373d9f9320f69f24b080ee00d10f14397355 (patch)
tree6f52ae0d0b524e2bfa79abbe3676771523cb63b2
parentbe6257b251cebd2deb8c76d43e387e28e3f7412d (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.c67
-rw-r--r--fs/quota/quota_v2.c6
-rw-r--r--include/linux/dqblk_qtree.h2
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
25static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) 25static 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
35static 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 */
37static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) 43static 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}
670EXPORT_SYMBOL(qtree_release_dquot); 676EXPORT_SYMBOL(qtree_release_dquot);
677
678static 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 }
717out_buf:
718 kfree(buf);
719 return ret;
720}
721
722int 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}
733EXPORT_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
307static 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
307static const struct quota_format_ops v2_format_ops = { 312static 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
317static struct quota_format_type v2r0_quota_format = { 323static 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
17struct dquot; 17struct dquot;
18struct kqid;
18 19
19/* Operations */ 20/* Operations */
20struct qtree_fmt_operations { 21struct 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}
56int 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 */