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