L4Re/departure

libext2fs/lib/libsupport/quotaio_tree.c

617:2733e5770ee9
9 months ago Paul Boddie Made the run command wait for completion, introducing the spawn command to run programs in the background. Introduced conveniences for waiting for the last job to be initiated and for piping from the last job, also subscribing to signals from pipe-supplying jobs so that they may be transparently removed from the job list upon completion. Augmented the job listing with the "+" notation familiar from Unix. Prevented new jobs from being started when no job slots are available.
     1 /*     2  * Implementation of new quotafile format     3  *     4  * Jan Kara <jack@suse.cz> - sponsored by SuSE CR     5  */     6      7 #include "config.h"     8 #include <sys/types.h>     9 #include <errno.h>    10 #include <stdio.h>    11 #include <stdlib.h>    12 #include <string.h>    13 #include <unistd.h>    14     15 #include "common.h"    16 #include "quotaio_tree.h"    17 #include "quotaio.h"    18     19 typedef char *dqbuf_t;    20     21 #define freedqbuf(buf)		ext2fs_free_mem(&buf)    22     23 static inline dqbuf_t getdqbuf(void)    24 {    25 	dqbuf_t buf;    26 	if (ext2fs_get_memzero(QT_BLKSIZE, &buf)) {    27 		log_err("Failed to allocate dqbuf");    28 		return NULL;    29 	}    30     31 	return buf;    32 }    33     34 /* Is given dquot empty? */    35 int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk)    36 {    37 	unsigned int i;    38     39 	for (i = 0; i < info->dqi_entry_size; i++)    40 		if (disk[i])    41 			return 0;    42 	return 1;    43 }    44     45 int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info)    46 {    47 	return (QT_BLKSIZE - sizeof(struct qt_disk_dqdbheader)) /    48 		info->dqi_entry_size;    49 }    50     51 static int get_index(qid_t id, int depth)    52 {    53 	return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff;    54 }    55     56 static inline void mark_quotafile_info_dirty(struct quota_handle *h)    57 {    58 	h->qh_io_flags |= IOFL_INFODIRTY;    59 }    60     61 /* Read given block */    62 static void read_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf)    63 {    64 	int err;    65     66 	err = h->e2fs_read(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf,    67 			QT_BLKSIZE);    68 	if (err < 0)    69 		log_err("Cannot read block %u: %s", blk, strerror(errno));    70 	else if (err != QT_BLKSIZE)    71 		memset(buf + err, 0, QT_BLKSIZE - err);    72 }    73     74 /* Write block */    75 static int write_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf)    76 {    77 	int err;    78     79 	err = h->e2fs_write(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf,    80 			QT_BLKSIZE);    81 	if (err < 0 && errno != ENOSPC)    82 		log_err("Cannot write block (%u): %s", blk, strerror(errno));    83 	if (err != QT_BLKSIZE)    84 		return -ENOSPC;    85 	return 0;    86 }    87     88 /* Get free block in file (either from free list or create new one) */    89 static int get_free_dqblk(struct quota_handle *h)    90 {    91 	dqbuf_t buf = getdqbuf();    92 	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;    93 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;    94 	int blk;    95     96 	if (!buf)    97 		return -ENOMEM;    98     99 	if (info->dqi_free_blk) {   100 		blk = info->dqi_free_blk;   101 		read_blk(h, blk, buf);   102 		info->dqi_free_blk = ext2fs_le32_to_cpu(dh->dqdh_next_free);   103 	} else {   104 		memset(buf, 0, QT_BLKSIZE);   105 		/* Assure block allocation... */   106 		if (write_blk(h, info->dqi_blocks, buf) < 0) {   107 			freedqbuf(buf);   108 			log_err("Cannot allocate new quota block "   109 				"(out of disk space).");   110 			return -ENOSPC;   111 		}   112 		blk = info->dqi_blocks++;   113 	}   114 	mark_quotafile_info_dirty(h);   115 	freedqbuf(buf);   116 	return blk;   117 }   118    119 /* Put given block to free list */   120 static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf,   121 			   unsigned int blk)   122 {   123 	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;   124 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;   125    126 	dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_blk);   127 	dh->dqdh_prev_free = ext2fs_cpu_to_le32(0);   128 	dh->dqdh_entries = ext2fs_cpu_to_le16(0);   129 	info->dqi_free_blk = blk;   130 	mark_quotafile_info_dirty(h);   131 	write_blk(h, blk, buf);   132 }   133    134 /* Remove given block from the list of blocks with free entries */   135 static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf,   136 				unsigned int blk)   137 {   138 	dqbuf_t tmpbuf = getdqbuf();   139 	struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf;   140 	unsigned int nextblk = ext2fs_le32_to_cpu(dh->dqdh_next_free), prevblk =   141    142 		ext2fs_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 = ext2fs_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 */   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 = ext2fs_cpu_to_le32(info->dqi_free_entry);   180 	dh->dqdh_prev_free = ext2fs_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 				ext2fs_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 */   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 (ext2fs_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 		ext2fs_cpu_to_le16(ext2fs_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 */   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 = ext2fs_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 			ext2fs_cpu_to_le32(newblk);   294 		write_blk(h, *treeblk, buf);   295 	} else if (newact && ret < 0) {   296 		put_free_dqblk(h, buf, *treeblk);   297 	}   298    299 out_buf:   300 	freedqbuf(buf);   301 	return ret;   302 }   303    304 /* Wrapper for inserting quota structure into tree */   305 static void dq_insert_tree(struct quota_handle *h, struct dquot *dquot)   306 {   307 	unsigned int tmp = QT_TREEOFF;   308    309 	if (do_insert_tree(h, dquot, &tmp, 0) < 0)   310 		log_err("Cannot write quota (id %u): %s",   311 			(unsigned int) dquot->dq_id, strerror(errno));   312 }   313    314 /* Write dquot to file */   315 void qtree_write_dquot(struct dquot *dquot)   316 {   317 	errcode_t retval;   318 	unsigned int ret;   319 	char *ddquot;   320 	struct quota_handle *h = dquot->dq_h;   321 	struct qtree_mem_dqinfo *info =   322 			&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree;   323 	log_debug("writing ddquot 1: off=%llu, info->dqi_entry_size=%u",   324 			dquot->dq_dqb.u.v2_mdqb.dqb_off,   325 			info->dqi_entry_size);   326 	retval = ext2fs_get_mem(info->dqi_entry_size, &ddquot);   327 	if (retval) {   328 		errno = ENOMEM;   329 		log_err("Quota write failed (id %u): %s",   330 			(unsigned int)dquot->dq_id, strerror(errno));   331 		return;   332 	}   333 	memset(ddquot, 0, info->dqi_entry_size);   334    335 	if (!dquot->dq_dqb.u.v2_mdqb.dqb_off)   336 		dq_insert_tree(dquot->dq_h, dquot);   337 	info->dqi_ops->mem2disk_dqblk(ddquot, dquot);   338 	log_debug("writing ddquot 2: off=%llu, info->dqi_entry_size=%u",   339 			dquot->dq_dqb.u.v2_mdqb.dqb_off,   340 			info->dqi_entry_size);   341 	ret = h->e2fs_write(&h->qh_qf, dquot->dq_dqb.u.v2_mdqb.dqb_off, ddquot,   342 			info->dqi_entry_size);   343    344 	if (ret != info->dqi_entry_size) {   345 		if (ret > 0)   346 			errno = ENOSPC;   347 		log_err("Quota write failed (id %u): %s",   348 			(unsigned int)dquot->dq_id, strerror(errno));   349 	}   350 	ext2fs_free_mem(&ddquot);   351 }   352    353 /* Free dquot entry in data block */   354 static void free_dqentry(struct quota_handle *h, struct dquot *dquot,   355 			 unsigned int blk)   356 {   357 	struct qt_disk_dqdbheader *dh;   358 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;   359 	dqbuf_t buf = getdqbuf();   360    361 	if (!buf)   362 		return;   363    364 	if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk)   365 		log_err("Quota structure has offset to other block (%u) "   366 			"than it should (%u).", blk,   367 			  (unsigned int) (dquot->dq_dqb.u.v2_mdqb.dqb_off >>   368 				  QT_BLKSIZE_BITS));   369    370 	read_blk(h, blk, buf);   371 	dh = (struct qt_disk_dqdbheader *)buf;   372 	dh->dqdh_entries =   373 		ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) - 1);   374    375 	if (!ext2fs_le16_to_cpu(dh->dqdh_entries)) {	/* Block got free? */   376 		remove_free_dqentry(h, buf, blk);   377 		put_free_dqblk(h, buf, blk);   378 	} else {   379 		memset(buf + (dquot->dq_dqb.u.v2_mdqb.dqb_off &   380 			      ((1 << QT_BLKSIZE_BITS) - 1)),   381 		       0, info->dqi_entry_size);   382    383 		/* First free entry? */   384 		if (ext2fs_le16_to_cpu(dh->dqdh_entries) ==   385 				qtree_dqstr_in_blk(info) - 1)   386 			/* This will also write data block */   387 			insert_free_dqentry(h, buf, blk);   388 		else   389 			write_blk(h, blk, buf);   390 	}   391 	dquot->dq_dqb.u.v2_mdqb.dqb_off = 0;   392 	freedqbuf(buf);   393 }   394    395 /* Remove reference to dquot from tree */   396 static void remove_tree(struct quota_handle *h, struct dquot *dquot,   397 			unsigned int * blk, int depth)   398 {   399 	dqbuf_t buf = getdqbuf();   400 	unsigned int newblk;   401 	__le32 *ref = (__le32 *) buf;   402    403 	if (!buf)   404 		return;   405    406 	read_blk(h, *blk, buf);   407 	newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);   408 	if (depth == QT_TREEDEPTH - 1) {   409 		free_dqentry(h, dquot, newblk);   410 		newblk = 0;   411 	} else {   412 		remove_tree(h, dquot, &newblk, depth + 1);   413 	}   414    415 	if (!newblk) {   416 		int i;   417    418 		ref[get_index(dquot->dq_id, depth)] = ext2fs_cpu_to_le32(0);   419    420 		/* Block got empty? */   421 		for (i = 0; i < QT_BLKSIZE && !buf[i]; i++);   422    423 		/* Don't put the root block into the free block list */   424 		if (i == QT_BLKSIZE && *blk != QT_TREEOFF) {   425 			put_free_dqblk(h, buf, *blk);   426 			*blk = 0;   427 		} else {   428 			write_blk(h, *blk, buf);   429 		}   430 	}   431 	freedqbuf(buf);   432 }   433    434 /* Delete dquot from tree */   435 void qtree_delete_dquot(struct dquot *dquot)   436 {   437 	unsigned int tmp = QT_TREEOFF;   438    439 	if (!dquot->dq_dqb.u.v2_mdqb.dqb_off)	/* Even not allocated? */   440 		return;   441 	remove_tree(dquot->dq_h, dquot, &tmp, 0);   442 }   443    444 /* Find entry in block */   445 static ext2_loff_t find_block_dqentry(struct quota_handle *h,   446 				      struct dquot *dquot, unsigned int blk)   447 {   448 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;   449 	dqbuf_t buf = getdqbuf();   450 	int i;   451 	char *ddquot = buf + sizeof(struct qt_disk_dqdbheader);   452    453 	if (!buf)   454 		return -ENOMEM;   455    456 	read_blk(h, blk, buf);   457 	for (i = 0;   458 	     i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot);   459 	     i++)   460 		ddquot += info->dqi_entry_size;   461    462 	if (i == qtree_dqstr_in_blk(info))   463 		log_err("Quota for id %u referenced but not present.",   464 			dquot->dq_id);   465 	freedqbuf(buf);   466 	return (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) +   467 		i * info->dqi_entry_size;   468 }   469    470 /* Find entry for given id in the tree */   471 static ext2_loff_t find_tree_dqentry(struct quota_handle *h,   472 				     struct dquot *dquot,   473 				     unsigned int blk, int depth)   474 {   475 	dqbuf_t buf = getdqbuf();   476 	ext2_loff_t ret = 0;   477 	__le32 *ref = (__le32 *) buf;   478    479 	if (!buf)   480 		return -ENOMEM;   481    482 	read_blk(h, blk, buf);   483 	ret = 0;   484 	blk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]);   485 	if (!blk)	/* No reference? */   486 		goto out_buf;   487 	if (depth < QT_TREEDEPTH - 1)   488 		ret = find_tree_dqentry(h, dquot, blk, depth + 1);   489 	else   490 		ret = find_block_dqentry(h, dquot, blk);   491 out_buf:   492 	freedqbuf(buf);   493 	return ret;   494 }   495    496 /* Find entry for given id in the tree - wrapper function */   497 static inline ext2_loff_t find_dqentry(struct quota_handle *h,   498 				       struct dquot *dquot)   499 {   500 	return find_tree_dqentry(h, dquot, QT_TREEOFF, 0);   501 }   502    503 /*   504  *  Read dquot from disk.   505  */   506 struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id)   507 {   508 	struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree;   509 	ext2_loff_t offset;   510 	unsigned int ret;   511 	char *ddquot;   512 	struct dquot *dquot = get_empty_dquot();   513    514 	if (!dquot)   515 		return NULL;   516 	if (ext2fs_get_mem(info->dqi_entry_size, &ddquot)) {   517 		ext2fs_free_mem(&dquot);   518 		return NULL;   519 	}   520    521 	dquot->dq_id = id;   522 	dquot->dq_h = h;   523 	dquot->dq_dqb.u.v2_mdqb.dqb_off = 0;   524 	memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk));   525    526 	offset = find_dqentry(h, dquot);   527 	if (offset > 0) {   528 		dquot->dq_dqb.u.v2_mdqb.dqb_off = offset;   529 		ret = h->e2fs_read(&h->qh_qf, offset, ddquot,   530 			info->dqi_entry_size);   531 		if (ret != info->dqi_entry_size) {   532 			if (ret > 0)   533 				errno = EIO;   534 			log_err("Cannot read quota structure for id %u: %s",   535 				dquot->dq_id, strerror(errno));   536 		}   537 		info->dqi_ops->disk2mem_dqblk(dquot, ddquot);   538 	}   539 	ext2fs_free_mem(&ddquot);   540 	return dquot;   541 }   542    543 static int check_reference(struct quota_handle *h, unsigned int blk)   544 {   545 	if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) {   546 		log_err("Illegal reference (%u >= %u) in %s quota file",   547 			blk, h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks,   548 			quota_type2name(h->qh_type));   549 		return -1;   550 	}   551 	return 0;   552 }   553    554 /*   555  * Scan all dquots in file and call callback on each   556  */   557 #define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7)))   558 #define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7)))   559    560 static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap,   561 			int (*process_dquot) (struct dquot *, void *),   562 			void *data)   563 {   564 	struct qtree_mem_dqinfo *info =   565 			&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree;   566 	dqbuf_t buf = getdqbuf();   567 	struct qt_disk_dqdbheader *dh;   568 	char *ddata;   569 	int entries, i;   570    571 	if (!buf)   572 		return -1;   573    574 	set_bit(bitmap, blk);   575 	read_blk(dquot->dq_h, blk, buf);   576 	dh = (struct qt_disk_dqdbheader *)buf;   577 	ddata = buf + sizeof(struct qt_disk_dqdbheader);   578 	entries = ext2fs_le16_to_cpu(dh->dqdh_entries);   579 	for (i = 0; i < qtree_dqstr_in_blk(info);   580 			i++, ddata += info->dqi_entry_size)   581 		if (!qtree_entry_unused(info, ddata)) {   582 			dquot->dq_dqb.u.v2_mdqb.dqb_off =   583 				(blk << QT_BLKSIZE_BITS) +   584 				sizeof(struct qt_disk_dqdbheader) +   585 				i * info->dqi_entry_size;   586 			info->dqi_ops->disk2mem_dqblk(dquot, ddata);   587 			if (process_dquot(dquot, data) < 0)   588 				break;   589 		}   590 	freedqbuf(buf);   591 	return entries;   592 }   593    594 static int report_tree(struct dquot *dquot, unsigned int blk, int depth,   595 		       char *bitmap,   596 		       int (*process_dquot) (struct dquot *, void *),   597 		       void *data)   598 {   599 	int entries = 0, ret, i;   600 	dqbuf_t buf = getdqbuf();   601 	__le32 *ref = (__le32 *) buf;   602    603 	if (!buf)   604 		return 0;   605    606 	read_blk(dquot->dq_h, blk, buf);   607 	if (depth == QT_TREEDEPTH - 1) {   608 		for (i = 0; i < QT_BLKSIZE >> 2; i++) {   609 			blk = ext2fs_le32_to_cpu(ref[i]);   610 			if (check_reference(dquot->dq_h, blk)) {   611 				entries = -1;   612 				goto errout;   613 			}   614 			if (blk && !get_bit(bitmap, blk)) {   615 				ret = report_block(dquot, blk, bitmap,   616 						   process_dquot, data);   617 				if (ret < 0) {   618 					entries = ret;   619 					goto errout;   620 				}   621 				entries += ret;   622 			}   623 		}   624 	} else {   625 		for (i = 0; i < QT_BLKSIZE >> 2; i++) {   626 			blk = ext2fs_le32_to_cpu(ref[i]);   627 			if (blk) {   628 				if (check_reference(dquot->dq_h, blk)) {   629 					entries = -1;   630 					goto errout;   631 				}   632 				ret = report_tree(dquot, blk, depth + 1,   633 						  bitmap, process_dquot,   634 						  data);   635 				if (ret < 0) {   636 					entries = ret;   637 					goto errout;   638 				}   639 				entries += ret;   640 			}   641 		}   642 	}   643 errout:   644 	freedqbuf(buf);   645 	return entries;   646 }   647    648 static unsigned int find_set_bits(char *bmp, int blocks)   649 {   650 	unsigned int	used = 0;   651 	int		i;   652    653 	for (i = 0; i < blocks; i++)   654 		if (get_bit(bmp, i))   655 			used++;   656 	return used;   657 }   658    659 int qtree_scan_dquots(struct quota_handle *h,   660 		      int (*process_dquot) (struct dquot *, void *),   661 		      void *data)   662 {   663 	int ret;   664 	char *bitmap;   665 	struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi;   666 	struct qtree_mem_dqinfo *info = &v2info->dqi_qtree;   667 	struct dquot *dquot = get_empty_dquot();   668    669 	if (!dquot)   670 		return -1;   671    672 	dquot->dq_h = h;   673 	if (ext2fs_get_memzero((info->dqi_blocks + 7) >> 3, &bitmap)) {   674 		ext2fs_free_mem(&dquot);   675 		return -1;   676 	}   677 	ret = report_tree(dquot, QT_TREEOFF, 0, bitmap, process_dquot, data);   678 	if (ret < 0)   679 		goto errout;   680 	v2info->dqi_used_entries = ret;   681 	v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks);   682 	ret = 0;   683 errout:   684 	ext2fs_free_mem(&bitmap);   685 	ext2fs_free_mem(&dquot);   686 	return ret;   687 }