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