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