|
@@ -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);
|