Skip to content

Commit

Permalink
quota_v2: Implement get_next_id() for V2 quota format
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jan Kara committed Feb 9, 2016
1 parent be6257b commit 0066373
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 2 deletions.
67 changes: 65 additions & 2 deletions fs/quota/quota_tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,23 @@ 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--)
id /= epb;
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)
{
Expand Down Expand Up @@ -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);
6 changes: 6 additions & 0 deletions fs/quota/quota_v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 = {
Expand Down
2 changes: 2 additions & 0 deletions include/linux/dqblk_qtree.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define QTREE_DEL_REWRITE 6

struct dquot;
struct kqid;

/* Operations */
struct qtree_fmt_operations {
Expand Down Expand Up @@ -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 */

0 comments on commit 0066373

Please sign in to comment.