1 /*
2  * Implementation of new quotafile format
3  *
4  * Jan Kara <jack@suse.cz> - sponsored by SuSE CR
5  * Hyojun Kim <hyojun@google.com> - Ported to f2fs-tools
6  */
7 
8 #include "config.h"
9 #include <sys/types.h>
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 
16 #include "common.h"
17 #include "quotaio_tree.h"
18 #include "quotaio.h"
19 
20 typedef char *dqbuf_t;
21 
22 #define freedqbuf(buf)		quota_free_mem(&buf)
23 
getdqbuf(void)24 static inline dqbuf_t getdqbuf(void)
25 {
26 	dqbuf_t buf;
27 	if (quota_get_memzero(QT_BLKSIZE, &buf)) {
28 		log_err("Failed to allocate dqbuf");
29 		return NULL;
30 	}
31 
32 	return buf;
33 }
34 
35 /* Is given dquot empty? */
qtree_entry_unused(struct qtree_mem_dqinfo * info,char * disk)36 int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk)
37 {
38 	unsigned int i;
39 
40 	for (i = 0; i < info->dqi_entry_size; i++)
41 		if (disk[i])
42 			return 0;
43 	return 1;
44 }
45 
qtree_dqstr_in_blk(struct qtree_mem_dqinfo * info)46 int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info)
47 {
48 	return (QT_BLKSIZE - sizeof(struct qt_disk_dqdbheader)) /
49 		info->dqi_entry_size;
50 }
51 
get_index(qid_t id,int depth)52 static int get_index(qid_t id, int depth)
53 {
54 	return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff;
55 }
56 
mark_quotafile_info_dirty(struct quota_handle * h)57 static inline void mark_quotafile_info_dirty(struct quota_handle *h)
58 {
59 	h->qh_io_flags |= IOFL_INFODIRTY;
60 }
61 
62 /* Read given block */
read_blk(struct quota_handle * h,unsigned int blk,dqbuf_t buf)63 static void read_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf)
64 {
65 	int err;
66 
67 	err = h->read(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf,
68 			QT_BLKSIZE);
69 	if (err < 0)
70 		log_err("Cannot read block %u: %s", blk, strerror(errno));
71 	else if (err != QT_BLKSIZE)
72 		memset(buf + err, 0, QT_BLKSIZE - err);
73 }
74 
75 /* Write block */
write_blk(struct quota_handle * h,unsigned int blk,dqbuf_t buf)76 static int write_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf)
77 {
78 	int err;
79 
80 	err = h->write(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf,
81 			QT_BLKSIZE);
82 	if (err < 0 && errno != ENOSPC)
83 		log_err("Cannot write block (%u): %s", blk, strerror(errno));
84 	if (err != QT_BLKSIZE)
85 		return -ENOSPC;
86 	return 0;
87 }
88 
89 /* Get free block in file (either from free list or create new one) */
get_free_dqblk(struct quota_handle * h)90 static int get_free_dqblk(struct quota_handle *h)
91 {
92 	dqbuf_t buf = getdqbuf();
93 	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
94 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
95 	int blk;
96 
97 	if (!buf)
98 		return -ENOMEM;
99 
100 	if (info->dqi_free_blk) {
101 		blk = info->dqi_free_blk;
102 		read_blk(h, blk, buf);
103 		info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
104 	} else {
105 		memset(buf, 0, QT_BLKSIZE);
106 		/* Assure block allocation... */
107 		if (write_blk(h, info->dqi_blocks, buf) < 0) {
108 			freedqbuf(buf);
109 			log_err("Cannot allocate new quota block "
110 				"(out of disk space).");
111 			return -ENOSPC;
112 		}
113 		blk = info->dqi_blocks++;
114 	}
115 	mark_quotafile_info_dirty(h);
116 	freedqbuf(buf);
117 	return blk;
118 }
119 
120 /* Put given block to free list */
put_free_dqblk(struct quota_handle * h,dqbuf_t buf,unsigned int blk)121 static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf,
122 			   unsigned int blk)
123 {
124 	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
125 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
126 
127 	dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
128 	dh->dqdh_prev_free = cpu_to_le32(0);
129 	dh->dqdh_entries = cpu_to_le16(0);
130 	info->dqi_free_blk = blk;
131 	mark_quotafile_info_dirty(h);
132 	write_blk(h, blk, buf);
133 }
134 
135 /* Remove given block from the list of blocks with free entries */
remove_free_dqentry(struct quota_handle * h,dqbuf_t buf,unsigned int blk)136 static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf,
137 				unsigned int blk)
138 {
139 	dqbuf_t tmpbuf = getdqbuf();
140 	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
141 	unsigned int nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk =
142 		le32_to_cpu(dh->dqdh_prev_free);
143 
144 	if (!tmpbuf)
145 		return;
146 
147 	if (nextblk) {
148 		read_blk(h, nextblk, tmpbuf);
149 		((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
150 				dh->dqdh_prev_free;
151 		write_blk(h, nextblk, tmpbuf);
152 	}
153 	if (prevblk) {
154 		read_blk(h, prevblk, tmpbuf);
155 		((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free =
156 				dh->dqdh_next_free;
157 		write_blk(h, prevblk, tmpbuf);
158 	} else {
159 		h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = nextblk;
160 		mark_quotafile_info_dirty(h);
161 	}
162 	freedqbuf(tmpbuf);
163 	dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
164 	write_blk(h, blk, buf);	/* No matter whether write succeeds
165 				 * block is out of list */
166 }
167 
168 /* Insert given block to the beginning of list with free entries */
insert_free_dqentry(struct quota_handle * h,dqbuf_t buf,unsigned int blk)169 static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf,
170 				unsigned int blk)
171 {
172 	dqbuf_t tmpbuf = getdqbuf();
173 	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;
174 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
175 
176 	if (!tmpbuf)
177 		return;
178 
179 	dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
180 	dh->dqdh_prev_free = cpu_to_le32(0);
181 	write_blk(h, blk, buf);
182 	if (info->dqi_free_entry) {
183 		read_blk(h, info->dqi_free_entry, tmpbuf);
184 		((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
185 				cpu_to_le32(blk);
186 		write_blk(h, info->dqi_free_entry, tmpbuf);
187 	}
188 	freedqbuf(tmpbuf);
189 	info->dqi_free_entry = blk;
190 	mark_quotafile_info_dirty(h);
191 }
192 
193 /* Find space for dquot */
find_free_dqentry(struct quota_handle * h,struct dquot * dquot,int * err)194 static unsigned int find_free_dqentry(struct quota_handle *h,
195 				      struct dquot *dquot, int *err)
196 {
197 	int blk, i;
198 	struct qt_disk_dqdbheader *dh;
199 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
200 	char *ddquot;
201 	dqbuf_t buf;
202 
203 	*err = 0;
204 	buf = getdqbuf();
205 	if (!buf) {
206 		*err = -ENOMEM;
207 		return 0;
208 	}
209 
210 	dh = (struct qt_disk_dqdbheader *)buf;
211 	if (info->dqi_free_entry) {
212 		blk = info->dqi_free_entry;
213 		read_blk(h, blk, buf);
214 	} else {
215 		blk = get_free_dqblk(h);
216 		if (blk < 0) {
217 			freedqbuf(buf);
218 			*err = blk;
219 			return 0;
220 		}
221 		memset(buf, 0, QT_BLKSIZE);
222 		info->dqi_free_entry = blk;
223 		mark_quotafile_info_dirty(h);
224 	}
225 
226 	/* Block will be full? */
227 	if (le16_to_cpu(dh->dqdh_entries) + 1 >=
228 	    qtree_dqstr_in_blk(info))
229 		remove_free_dqentry(h, buf, blk);
230 
231 	dh->dqdh_entries =
232 		cpu_to_le16(le16_to_cpu(dh->dqdh_entries) + 1);
233 	/* Find free structure in block */
234 	ddquot = buf + sizeof(struct qt_disk_dqdbheader);
235 	for (i = 0;
236 	     i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot);
237 	     i++)
238 		ddquot += info->dqi_entry_size;
239 
240 	if (i == qtree_dqstr_in_blk(info))
241 		log_err("find_free_dqentry(): Data block full unexpectedly.");
242 
243 	write_blk(h, blk, buf);
244 	dquot->dq_dqb.u.v2_mdqb.dqb_off =
245 		(blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) +
246 		i * info->dqi_entry_size;
247 	freedqbuf(buf);
248 	return blk;
249 }
250 
251 /* Insert reference to structure into the trie */
do_insert_tree(struct quota_handle * h,struct dquot * dquot,unsigned int * treeblk,int depth)252 static int do_insert_tree(struct quota_handle *h, struct dquot *dquot,
253 			  unsigned int * treeblk, int depth)
254 {
255 	dqbuf_t buf;
256 	int newson = 0, newact = 0;
257 	__le32 *ref;
258 	unsigned int newblk;
259 	int ret = 0;
260 
261 	log_debug("inserting in tree: treeblk=%u, depth=%d", *treeblk, depth);
262 	buf = getdqbuf();
263 	if (!buf)
264 		return -ENOMEM;
265 
266 	if (!*treeblk) {
267 		ret = get_free_dqblk(h);
268 		if (ret < 0)
269 			goto out_buf;
270 		*treeblk = ret;
271 		memset(buf, 0, QT_BLKSIZE);
272 		newact = 1;
273 	} else {
274 		read_blk(h, *treeblk, buf);
275 	}
276 
277 	ref = (__le32 *) buf;
278 	newblk = le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);
279 	if (!newblk)
280 		newson = 1;
281 	if (depth == QT_TREEDEPTH - 1) {
282 		if (newblk)
283 			log_err("Inserting already present quota entry "
284 				"(block %u).",
285 				ref[get_index(dquot->dq_id, depth)]);
286 		newblk = find_free_dqentry(h, dquot, &ret);
287 	} else {
288 		ret = do_insert_tree(h, dquot, &newblk, depth + 1);
289 	}
290 
291 	if (newson && ret >= 0) {
292 		ref[get_index(dquot->dq_id, depth)] =
293 			cpu_to_le32(newblk);
294 		ret = write_blk(h, *treeblk, buf);
295 		if (ret)
296 			goto out_buf;
297 	} else if (newact && ret < 0) {
298 		put_free_dqblk(h, buf, *treeblk);
299 	}
300 
301 out_buf:
302 	freedqbuf(buf);
303 	return ret;
304 }
305 
306 /* Wrapper for inserting quota structure into tree */
dq_insert_tree(struct quota_handle * h,struct dquot * dquot)307 static int dq_insert_tree(struct quota_handle *h, struct dquot *dquot)
308 {
309 	unsigned int tmp = QT_TREEOFF;
310 	int err;
311 
312 	err = do_insert_tree(h, dquot, &tmp, 0);
313 	if (err < 0)
314 		log_err("Cannot write quota (id %u): %s",
315 			(unsigned int) dquot->dq_id, strerror(errno));
316 	return err;
317 }
318 
319 /* Write dquot to file */
qtree_write_dquot(struct dquot * dquot)320 int qtree_write_dquot(struct dquot *dquot)
321 {
322 	errcode_t retval;
323 	unsigned int ret;
324 	char *ddquot;
325 	struct quota_handle *h = dquot->dq_h;
326 	struct qtree_mem_dqinfo *info =
327 			&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree;
328 
329 	log_debug("writing ddquot 1: off=%llu, info->dqi_entry_size=%u",
330 			dquot->dq_dqb.u.v2_mdqb.dqb_off,
331 			info->dqi_entry_size);
332 	retval = quota_get_mem(info->dqi_entry_size, &ddquot);
333 	if (retval) {
334 		log_err("Quota write failed (id %u): %s",
335 			(unsigned int)dquot->dq_id, strerror(errno));
336 		return -ENOMEM;
337 	}
338 	memset(ddquot, 0, info->dqi_entry_size);
339 
340 	if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) {
341 		if (dq_insert_tree(dquot->dq_h, dquot)) {
342 			quota_free_mem(&ddquot);
343 			return -EIO;
344 		}
345 	}
346 	info->dqi_ops->mem2disk_dqblk(ddquot, dquot);
347 	log_debug("writing ddquot 2: off=%llu, info->dqi_entry_size=%u",
348 			dquot->dq_dqb.u.v2_mdqb.dqb_off,
349 			info->dqi_entry_size);
350 	ret = h->write(&h->qh_qf, dquot->dq_dqb.u.v2_mdqb.dqb_off, ddquot,
351 			info->dqi_entry_size);
352 
353 	if (ret != info->dqi_entry_size) {
354 		log_err("Quota write failed (id %u): %s",
355 			(unsigned int)dquot->dq_id, strerror(errno));
356 		return ret;
357 	}
358 	quota_free_mem(&ddquot);
359 	return 0;
360 }
361 
362 /* Free dquot entry in data block */
free_dqentry(struct quota_handle * h,struct dquot * dquot,unsigned int blk)363 static void free_dqentry(struct quota_handle *h, struct dquot *dquot,
364 			 unsigned int blk)
365 {
366 	struct qt_disk_dqdbheader *dh;
367 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
368 	dqbuf_t buf = getdqbuf();
369 
370 	if (!buf)
371 		return;
372 
373 	if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk)
374 		log_err("Quota structure has offset to other block (%u) "
375 			"than it should (%u).", blk,
376 			  (unsigned int) (dquot->dq_dqb.u.v2_mdqb.dqb_off >>
377 				  QT_BLKSIZE_BITS));
378 
379 	read_blk(h, blk, buf);
380 	dh = (struct qt_disk_dqdbheader *)buf;
381 	dh->dqdh_entries =
382 		cpu_to_le16(le16_to_cpu(dh->dqdh_entries) - 1);
383 
384 	if (!le16_to_cpu(dh->dqdh_entries)) {	/* Block got free? */
385 		remove_free_dqentry(h, buf, blk);
386 		put_free_dqblk(h, buf, blk);
387 	} else {
388 		memset(buf + (dquot->dq_dqb.u.v2_mdqb.dqb_off &
389 			      ((1 << QT_BLKSIZE_BITS) - 1)),
390 		       0, info->dqi_entry_size);
391 
392 		/* First free entry? */
393 		if (le16_to_cpu(dh->dqdh_entries) ==
394 				qtree_dqstr_in_blk(info) - 1)
395 			/* This will also write data block */
396 			insert_free_dqentry(h, buf, blk);
397 		else
398 			write_blk(h, blk, buf);
399 	}
400 	dquot->dq_dqb.u.v2_mdqb.dqb_off = 0;
401 	freedqbuf(buf);
402 }
403 
404 /* Remove reference to dquot from tree */
remove_tree(struct quota_handle * h,struct dquot * dquot,unsigned int * blk,int depth)405 static void remove_tree(struct quota_handle *h, struct dquot *dquot,
406 			unsigned int * blk, int depth)
407 {
408 	dqbuf_t buf = getdqbuf();
409 	unsigned int newblk;
410 	__le32 *ref = (__le32 *) buf;
411 
412 	if (!buf)
413 		return;
414 
415 	read_blk(h, *blk, buf);
416 	newblk = le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);
417 	if (depth == QT_TREEDEPTH - 1) {
418 		free_dqentry(h, dquot, newblk);
419 		newblk = 0;
420 	} else {
421 		remove_tree(h, dquot, &newblk, depth + 1);
422 	}
423 
424 	if (!newblk) {
425 		int i;
426 
427 		ref[get_index(dquot->dq_id, depth)] = cpu_to_le32(0);
428 
429 		/* Block got empty? */
430 		for (i = 0; i < QT_BLKSIZE && !buf[i]; i++);
431 
432 		/* Don't put the root block into the free block list */
433 		if (i == QT_BLKSIZE && *blk != QT_TREEOFF) {
434 			put_free_dqblk(h, buf, *blk);
435 			*blk = 0;
436 		} else {
437 			write_blk(h, *blk, buf);
438 		}
439 	}
440 	freedqbuf(buf);
441 }
442 
443 /* Delete dquot from tree */
qtree_delete_dquot(struct dquot * dquot)444 void qtree_delete_dquot(struct dquot *dquot)
445 {
446 	unsigned int tmp = QT_TREEOFF;
447 
448 	if (!dquot->dq_dqb.u.v2_mdqb.dqb_off)	/* Even not allocated? */
449 		return;
450 	remove_tree(dquot->dq_h, dquot, &tmp, 0);
451 }
452 
453 /* Find entry in block */
find_block_dqentry(struct quota_handle * h,struct dquot * dquot,unsigned int blk)454 static long find_block_dqentry(struct quota_handle *h,
455 				      struct dquot *dquot, unsigned int blk)
456 {
457 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
458 	dqbuf_t buf = getdqbuf();
459 	int i;
460 	char *ddquot = buf + sizeof(struct qt_disk_dqdbheader);
461 
462 	if (!buf)
463 		return -ENOMEM;
464 
465 	read_blk(h, blk, buf);
466 	for (i = 0;
467 	     i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot);
468 	     i++)
469 		ddquot += info->dqi_entry_size;
470 
471 	if (i == qtree_dqstr_in_blk(info))
472 		log_err("Quota for id %u referenced but not present.",
473 			dquot->dq_id);
474 	freedqbuf(buf);
475 	return (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) +
476 		i * info->dqi_entry_size;
477 }
478 
479 /* Find entry for given id in the tree */
find_tree_dqentry(struct quota_handle * h,struct dquot * dquot,unsigned int blk,int depth)480 static long find_tree_dqentry(struct quota_handle *h,
481 				     struct dquot *dquot,
482 				     unsigned int blk, int depth)
483 {
484 	dqbuf_t buf = getdqbuf();
485 	long ret = 0;
486 	__le32 *ref = (__le32 *) buf;
487 
488 	if (!buf)
489 		return -ENOMEM;
490 
491 	read_blk(h, blk, buf);
492 	ret = 0;
493 	blk = le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);
494 	if (!blk)	/* No reference? */
495 		goto out_buf;
496 	if (depth < QT_TREEDEPTH - 1)
497 		ret = find_tree_dqentry(h, dquot, blk, depth + 1);
498 	else
499 		ret = find_block_dqentry(h, dquot, blk);
500 out_buf:
501 	freedqbuf(buf);
502 	return ret;
503 }
504 
505 /* Find entry for given id in the tree - wrapper function */
find_dqentry(struct quota_handle * h,struct dquot * dquot)506 static inline long find_dqentry(struct quota_handle *h,
507 				       struct dquot *dquot)
508 {
509 	return find_tree_dqentry(h, dquot, QT_TREEOFF, 0);
510 }
511 
512 /*
513  *  Read dquot from disk.
514  */
qtree_read_dquot(struct quota_handle * h,qid_t id)515 struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id)
516 {
517 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;
518 	long offset;
519 	unsigned int ret;
520 	char *ddquot;
521 	struct dquot *dquot = get_empty_dquot();
522 
523 	if (!dquot)
524 		return NULL;
525 	if (quota_get_mem(info->dqi_entry_size, &ddquot)) {
526 		quota_free_mem(&dquot);
527 		return NULL;
528 	}
529 
530 	dquot->dq_id = id;
531 	dquot->dq_h = h;
532 	dquot->dq_dqb.u.v2_mdqb.dqb_off = 0;
533 	memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk));
534 
535 	offset = find_dqentry(h, dquot);
536 	if (offset > 0) {
537 		dquot->dq_dqb.u.v2_mdqb.dqb_off = offset;
538 		ret = h->read(&h->qh_qf, offset, ddquot,
539 			info->dqi_entry_size);
540 		if (ret != info->dqi_entry_size) {
541 			if (ret > 0)
542 				errno = EIO;
543 			log_err("Cannot read quota structure for id %u: %s",
544 				dquot->dq_id, strerror(errno));
545 		}
546 		info->dqi_ops->disk2mem_dqblk(dquot, ddquot);
547 	}
548 	quota_free_mem(&ddquot);
549 	return dquot;
550 }
551 
552 /*
553  * Scan all dquots in file and call callback on each
554  */
555 #define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7)))
556 #define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7)))
557 
report_block(struct dquot * dquot,unsigned int blk,char * bitmap,int (* process_dquot)(struct dquot *,void *),void * data)558 static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap,
559 			int (*process_dquot) (struct dquot *, void *),
560 			void *data)
561 {
562 	struct qtree_mem_dqinfo *info =
563 			&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree;
564 	dqbuf_t buf = getdqbuf();
565 	struct qt_disk_dqdbheader *dh;
566 	char *ddata;
567 	int entries, i;
568 
569 	if (!buf)
570 		return 0;
571 
572 	set_bit(bitmap, blk);
573 	read_blk(dquot->dq_h, blk, buf);
574 	dh = (struct qt_disk_dqdbheader *)buf;
575 	ddata = buf + sizeof(struct qt_disk_dqdbheader);
576 	entries = le16_to_cpu(dh->dqdh_entries);
577 	for (i = 0; i < qtree_dqstr_in_blk(info);
578 			i++, ddata += info->dqi_entry_size)
579 		if (!qtree_entry_unused(info, ddata)) {
580 			dquot->dq_dqb.u.v2_mdqb.dqb_off =
581 				(blk << QT_BLKSIZE_BITS) +
582 				sizeof(struct qt_disk_dqdbheader) +
583 				i * info->dqi_entry_size;
584 			info->dqi_ops->disk2mem_dqblk(dquot, ddata);
585 			if (process_dquot(dquot, data) < 0)
586 				break;
587 		}
588 	freedqbuf(buf);
589 	return entries;
590 }
591 
check_reference(struct quota_handle * h,unsigned int blk)592 static int check_reference(struct quota_handle *h, unsigned int blk)
593 {
594 	if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) {
595 		log_err("Illegal reference (%u >= %u) in %s quota file. "
596 			"Quota file is probably corrupted.\n"
597 			"Please run fsck (8) to fix it.",
598 			blk,
599 			h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks,
600 			quota_type2name(h->qh_type));
601 		return -1;
602 	}
603 	return 0;
604 }
605 
606 /* Return 0 for successful run */
report_tree(struct dquot * dquot,unsigned int blk,int depth,char * bitmap,int * entries,int (* process_dquot)(struct dquot *,void *),void * data)607 static int report_tree(struct dquot *dquot, unsigned int blk, int depth,
608 		       char *bitmap, int *entries,
609 		       int (*process_dquot) (struct dquot *, void *),
610 		       void *data)
611 {
612 	int i;
613 	dqbuf_t buf = getdqbuf();
614 	__le32 *ref = (__le32 *) buf;
615 
616 	if (!buf)
617 		return -1;
618 
619 	read_blk(dquot->dq_h, blk, buf);
620 	for (i = 0; i < QT_BLKSIZE >> 2; i++) {
621 		blk = le32_to_cpu(ref[i]);
622 		if (blk == 0)
623 			continue;
624 
625 		if (check_reference(dquot->dq_h, blk))
626 			break;
627 
628 		if (depth == QT_TREEDEPTH - 1) {
629 			if (!get_bit(bitmap, blk))
630 				*entries += report_block(dquot, blk, bitmap,
631 							process_dquot, data);
632 		} else {
633 			if (report_tree(dquot, blk, depth + 1, bitmap, entries,
634 						process_dquot, data))
635 				break;
636 		}
637 	}
638 	freedqbuf(buf);
639 	return (i < QT_BLKSIZE >> 2) ? -1 : 0;
640 }
641 
find_set_bits(char * bmp,int blocks)642 static unsigned int find_set_bits(char *bmp, int blocks)
643 {
644 	unsigned int	used = 0;
645 	int		i;
646 
647 	for (i = 0; i < blocks; i++)
648 		if (get_bit(bmp, i))
649 			used++;
650 	return used;
651 }
652 
qtree_scan_dquots(struct quota_handle * h,int (* process_dquot)(struct dquot *,void *),void * data)653 int qtree_scan_dquots(struct quota_handle *h,
654 		      int (*process_dquot) (struct dquot *, void *),
655 		      void *data)
656 {
657 	struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi;
658 	struct qtree_mem_dqinfo *info = &v2info->dqi_qtree;
659 	struct dquot *dquot = get_empty_dquot();
660 	char *bitmap = NULL;
661 	int ret = -1;
662 	int entries = 0;
663 
664 	if (!dquot)
665 		return -1;
666 
667 	dquot->dq_h = h;
668 	if (quota_get_memzero((info->dqi_blocks + 7) >> 3, &bitmap))
669 		goto out;
670 	if (report_tree(dquot, QT_TREEOFF, 0, bitmap, &entries, process_dquot,
671 				data))
672 		goto out;
673 
674 	v2info->dqi_used_entries = entries;
675 	v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks);
676 	ret = 0;
677 
678 out:
679 	if (bitmap)
680 		quota_free_mem(&bitmap);
681 	if (dquot)
682 		quota_free_mem(&dquot);
683 
684 	return ret;
685 }
686