From be6257b251cebd2deb8c76d43e387e28e3f7412d Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 25 Jan 2016 19:24:50 +0100 Subject: quota: Add support for ->get_nextdqblk() for VFS quota Add infrastructure for supporting get_nextdqblk() callback for VFS quotas. Translate the operation into a callback to appropriate filesystem and consequently to quota format callback. Signed-off-by: Jan Kara --- include/linux/quota.h | 3 +++ include/linux/quotaops.h | 3 +++ 2 files changed, 6 insertions(+) (limited to 'include') diff --git a/include/linux/quota.h b/include/linux/quota.h index fba92f5c1a63..9dfb6bce8c9e 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -306,6 +306,7 @@ struct quota_format_ops { int (*read_dqblk)(struct dquot *dquot); /* Read structure for one user */ int (*commit_dqblk)(struct dquot *dquot); /* Write structure for one user */ int (*release_dqblk)(struct dquot *dquot); /* Called when last reference to dquot is being dropped */ + int (*get_next_id)(struct super_block *sb, struct kqid *qid); /* Get next ID with existing structure in the quota file */ }; /* Operations working with dquots */ @@ -321,6 +322,8 @@ struct dquot_operations { * quota code only */ qsize_t *(*get_reserved_space) (struct inode *); int (*get_projid) (struct inode *, kprojid_t *);/* Get project ID */ + /* Get next ID with active quota structure */ + int (*get_next_id) (struct super_block *sb, struct kqid *qid); }; struct path; diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 7a57c28eb5e7..f00fa86ac966 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -82,6 +82,7 @@ int dquot_commit(struct dquot *dquot); int dquot_acquire(struct dquot *dquot); int dquot_release(struct dquot *dquot); int dquot_commit_info(struct super_block *sb, int type); +int dquot_get_next_id(struct super_block *sb, struct kqid *qid); int dquot_mark_dquot_dirty(struct dquot *dquot); int dquot_file_open(struct inode *inode, struct file *file); @@ -99,6 +100,8 @@ int dquot_get_state(struct super_block *sb, struct qc_state *state); int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii); int dquot_get_dqblk(struct super_block *sb, struct kqid id, struct qc_dqblk *di); +int dquot_get_next_dqblk(struct super_block *sb, struct kqid *id, + struct qc_dqblk *di); int dquot_set_dqblk(struct super_block *sb, struct kqid id, struct qc_dqblk *di); -- cgit v1.2.3-70-g09d2 From 0066373d9f9320f69f24b080ee00d10f14397355 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 25 Jan 2016 20:39:27 +0100 Subject: 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 --- fs/quota/quota_tree.c | 67 +++++++++++++++++++++++++++++++++++++++++++-- fs/quota/quota_v2.c | 6 ++++ include/linux/dqblk_qtree.h | 2 ++ 3 files changed, 73 insertions(+), 2 deletions(-) (limited to 'include') 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"); #define __QUOTA_QT_PARANOIA -static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) +static int __get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth) { unsigned int epb = info->dqi_usable_bs >> 2; - qid_t id = from_kqid(&init_user_ns, qid); depth = info->dqi_qtree_depth - depth - 1; while (depth--) @@ -33,6 +32,13 @@ static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) return id % epb; } +static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) +{ + qid_t id = from_kqid(&init_user_ns, qid); + + return __get_index(info, id, depth); +} + /* Number of entries in one blocks */ static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) { @@ -668,3 +674,60 @@ int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) return 0; } EXPORT_SYMBOL(qtree_release_dquot); + +static int find_next_id(struct qtree_mem_dqinfo *info, qid_t *id, + unsigned int blk, int depth) +{ + char *buf = getdqbuf(info->dqi_usable_bs); + __le32 *ref = (__le32 *)buf; + ssize_t ret; + unsigned int epb = info->dqi_usable_bs >> 2; + unsigned int level_inc = 1; + int i; + + if (!buf) + return -ENOMEM; + + for (i = depth; i < info->dqi_qtree_depth - 1; i++) + level_inc *= epb; + + ret = read_blk(info, blk, buf); + if (ret < 0) { + quota_error(info->dqi_sb, + "Can't read quota tree block %u", blk); + goto out_buf; + } + for (i = __get_index(info, *id, depth); i < epb; i++) { + if (ref[i] == cpu_to_le32(0)) { + *id += level_inc; + continue; + } + if (depth == info->dqi_qtree_depth - 1) { + ret = 0; + goto out_buf; + } + ret = find_next_id(info, id, le32_to_cpu(ref[i]), depth + 1); + if (ret != -ENOENT) + break; + } + if (i == epb) { + ret = -ENOENT; + goto out_buf; + } +out_buf: + kfree(buf); + return ret; +} + +int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid) +{ + qid_t id = from_kqid(&init_user_ns, *qid); + int ret; + + ret = find_next_id(info, &id, QT_TREEOFF, 0); + if (ret < 0) + return ret; + *qid = make_kqid(&init_user_ns, qid->type, id); + return 0; +} +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) return 0; } +static int v2_get_next_id(struct super_block *sb, struct kqid *qid) +{ + return qtree_get_next_id(sb_dqinfo(sb, qid->type)->dqi_priv, qid); +} + static const struct quota_format_ops v2_format_ops = { .check_quota_file = v2_check_quota_file, .read_file_info = v2_read_file_info, @@ -312,6 +317,7 @@ static const struct quota_format_ops v2_format_ops = { .read_dqblk = v2_read_dquot, .commit_dqblk = v2_write_dquot, .release_dqblk = v2_release_dquot, + .get_next_id = v2_get_next_id, }; 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 @@ #define QTREE_DEL_REWRITE 6 struct dquot; +struct kqid; /* Operations */ struct qtree_fmt_operations { @@ -52,5 +53,6 @@ static inline int qtree_depth(struct qtree_mem_dqinfo *info) entries *= epb; return i; } +int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid); #endif /* _LINUX_DQBLK_QTREE_H */ -- cgit v1.2.3-70-g09d2