1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker * mkquota.c --- create quota files for a filesystem
3*6a54128fSAndroid Build Coastguard Worker *
4*6a54128fSAndroid Build Coastguard Worker * Aditya Kali <[email protected]>
5*6a54128fSAndroid Build Coastguard Worker */
6*6a54128fSAndroid Build Coastguard Worker #include "config.h"
7*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
8*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
9*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
10*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
11*6a54128fSAndroid Build Coastguard Worker #include <string.h>
12*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
13*6a54128fSAndroid Build Coastguard Worker
14*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2_fs.h"
15*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2fs.h"
16*6a54128fSAndroid Build Coastguard Worker #include "e2p/e2p.h"
17*6a54128fSAndroid Build Coastguard Worker
18*6a54128fSAndroid Build Coastguard Worker #include "quotaio.h"
19*6a54128fSAndroid Build Coastguard Worker #include "quotaio_v2.h"
20*6a54128fSAndroid Build Coastguard Worker #include "quotaio_tree.h"
21*6a54128fSAndroid Build Coastguard Worker #include "common.h"
22*6a54128fSAndroid Build Coastguard Worker #include "dict.h"
23*6a54128fSAndroid Build Coastguard Worker
24*6a54128fSAndroid Build Coastguard Worker /* Needed for architectures where sizeof(int) != sizeof(void *) */
25*6a54128fSAndroid Build Coastguard Worker #define UINT_TO_VOIDPTR(val) ((void *)(intptr_t)(val))
26*6a54128fSAndroid Build Coastguard Worker #define VOIDPTR_TO_UINT(ptr) ((unsigned int)(intptr_t)(ptr))
27*6a54128fSAndroid Build Coastguard Worker
28*6a54128fSAndroid Build Coastguard Worker #if DEBUG_QUOTA
print_inode(struct ext2_inode * inode)29*6a54128fSAndroid Build Coastguard Worker static void print_inode(struct ext2_inode *inode)
30*6a54128fSAndroid Build Coastguard Worker {
31*6a54128fSAndroid Build Coastguard Worker if (!inode)
32*6a54128fSAndroid Build Coastguard Worker return;
33*6a54128fSAndroid Build Coastguard Worker
34*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_mode = %d\n", inode->i_mode);
35*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_uid = %d\n", inode->i_uid);
36*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_size = %d\n", inode->i_size);
37*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_atime = %d\n", inode->i_atime);
38*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_ctime = %d\n", inode->i_ctime);
39*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_mtime = %d\n", inode->i_mtime);
40*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_dtime = %d\n", inode->i_dtime);
41*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_gid = %d\n", inode->i_gid);
42*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_links_count = %d\n", inode->i_links_count);
43*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_blocks = %d\n", inode->i_blocks);
44*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, " i_flags = %d\n", inode->i_flags);
45*6a54128fSAndroid Build Coastguard Worker
46*6a54128fSAndroid Build Coastguard Worker return;
47*6a54128fSAndroid Build Coastguard Worker }
48*6a54128fSAndroid Build Coastguard Worker
print_dquot(const char * desc,struct dquot * dq)49*6a54128fSAndroid Build Coastguard Worker static void print_dquot(const char *desc, struct dquot *dq)
50*6a54128fSAndroid Build Coastguard Worker {
51*6a54128fSAndroid Build Coastguard Worker if (desc)
52*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "%s: ", desc);
53*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "%u %lld:%lld:%lld %lld:%lld:%lld\n",
54*6a54128fSAndroid Build Coastguard Worker dq->dq_id, (long long) dq->dq_dqb.dqb_curspace,
55*6a54128fSAndroid Build Coastguard Worker (long long) dq->dq_dqb.dqb_bsoftlimit,
56*6a54128fSAndroid Build Coastguard Worker (long long) dq->dq_dqb.dqb_bhardlimit,
57*6a54128fSAndroid Build Coastguard Worker (long long) dq->dq_dqb.dqb_curinodes,
58*6a54128fSAndroid Build Coastguard Worker (long long) dq->dq_dqb.dqb_isoftlimit,
59*6a54128fSAndroid Build Coastguard Worker (long long) dq->dq_dqb.dqb_ihardlimit);
60*6a54128fSAndroid Build Coastguard Worker }
61*6a54128fSAndroid Build Coastguard Worker #else
print_dquot(const char * desc EXT2FS_ATTR ((unused)),struct dquot * dq EXT2FS_ATTR ((unused)))62*6a54128fSAndroid Build Coastguard Worker static void print_dquot(const char *desc EXT2FS_ATTR((unused)),
63*6a54128fSAndroid Build Coastguard Worker struct dquot *dq EXT2FS_ATTR((unused)))
64*6a54128fSAndroid Build Coastguard Worker {
65*6a54128fSAndroid Build Coastguard Worker }
66*6a54128fSAndroid Build Coastguard Worker #endif
67*6a54128fSAndroid Build Coastguard Worker
68*6a54128fSAndroid Build Coastguard Worker /*
69*6a54128fSAndroid Build Coastguard Worker * Returns 0 if not able to find the quota file, otherwise returns its
70*6a54128fSAndroid Build Coastguard Worker * inode number.
71*6a54128fSAndroid Build Coastguard Worker */
quota_file_exists(ext2_filsys fs,enum quota_type qtype)72*6a54128fSAndroid Build Coastguard Worker int quota_file_exists(ext2_filsys fs, enum quota_type qtype)
73*6a54128fSAndroid Build Coastguard Worker {
74*6a54128fSAndroid Build Coastguard Worker char qf_name[256];
75*6a54128fSAndroid Build Coastguard Worker errcode_t ret;
76*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino;
77*6a54128fSAndroid Build Coastguard Worker
78*6a54128fSAndroid Build Coastguard Worker if (qtype >= MAXQUOTAS)
79*6a54128fSAndroid Build Coastguard Worker return -EINVAL;
80*6a54128fSAndroid Build Coastguard Worker
81*6a54128fSAndroid Build Coastguard Worker quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name);
82*6a54128fSAndroid Build Coastguard Worker
83*6a54128fSAndroid Build Coastguard Worker ret = ext2fs_lookup(fs, EXT2_ROOT_INO, qf_name, strlen(qf_name), 0,
84*6a54128fSAndroid Build Coastguard Worker &ino);
85*6a54128fSAndroid Build Coastguard Worker if (ret)
86*6a54128fSAndroid Build Coastguard Worker return 0;
87*6a54128fSAndroid Build Coastguard Worker
88*6a54128fSAndroid Build Coastguard Worker return ino;
89*6a54128fSAndroid Build Coastguard Worker }
90*6a54128fSAndroid Build Coastguard Worker
91*6a54128fSAndroid Build Coastguard Worker /*
92*6a54128fSAndroid Build Coastguard Worker * Set the value for reserved quota inode number field in superblock.
93*6a54128fSAndroid Build Coastguard Worker */
quota_set_sb_inum(ext2_filsys fs,ext2_ino_t ino,enum quota_type qtype)94*6a54128fSAndroid Build Coastguard Worker void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, enum quota_type qtype)
95*6a54128fSAndroid Build Coastguard Worker {
96*6a54128fSAndroid Build Coastguard Worker ext2_ino_t *inump;
97*6a54128fSAndroid Build Coastguard Worker
98*6a54128fSAndroid Build Coastguard Worker inump = quota_sb_inump(fs->super, qtype);
99*6a54128fSAndroid Build Coastguard Worker
100*6a54128fSAndroid Build Coastguard Worker log_debug("setting quota ino in superblock: ino=%u, type=%d", ino,
101*6a54128fSAndroid Build Coastguard Worker qtype);
102*6a54128fSAndroid Build Coastguard Worker if (inump == NULL)
103*6a54128fSAndroid Build Coastguard Worker return;
104*6a54128fSAndroid Build Coastguard Worker *inump = ino;
105*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_super_dirty(fs);
106*6a54128fSAndroid Build Coastguard Worker }
107*6a54128fSAndroid Build Coastguard Worker
quota_remove_inode(ext2_filsys fs,enum quota_type qtype)108*6a54128fSAndroid Build Coastguard Worker errcode_t quota_remove_inode(ext2_filsys fs, enum quota_type qtype)
109*6a54128fSAndroid Build Coastguard Worker {
110*6a54128fSAndroid Build Coastguard Worker ext2_ino_t qf_ino;
111*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
112*6a54128fSAndroid Build Coastguard Worker
113*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_read_bitmaps(fs);
114*6a54128fSAndroid Build Coastguard Worker if (retval) {
115*6a54128fSAndroid Build Coastguard Worker log_debug("Couldn't read bitmaps: %s", error_message(retval));
116*6a54128fSAndroid Build Coastguard Worker return retval;
117*6a54128fSAndroid Build Coastguard Worker }
118*6a54128fSAndroid Build Coastguard Worker
119*6a54128fSAndroid Build Coastguard Worker qf_ino = *quota_sb_inump(fs->super, qtype);
120*6a54128fSAndroid Build Coastguard Worker if (qf_ino == 0)
121*6a54128fSAndroid Build Coastguard Worker return 0;
122*6a54128fSAndroid Build Coastguard Worker retval = quota_inode_truncate(fs, qf_ino);
123*6a54128fSAndroid Build Coastguard Worker if (retval)
124*6a54128fSAndroid Build Coastguard Worker return retval;
125*6a54128fSAndroid Build Coastguard Worker if (qf_ino >= EXT2_FIRST_INODE(fs->super)) {
126*6a54128fSAndroid Build Coastguard Worker struct ext2_inode inode;
127*6a54128fSAndroid Build Coastguard Worker
128*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_read_inode(fs, qf_ino, &inode);
129*6a54128fSAndroid Build Coastguard Worker if (!retval) {
130*6a54128fSAndroid Build Coastguard Worker memset(&inode, 0, sizeof(struct ext2_inode));
131*6a54128fSAndroid Build Coastguard Worker ext2fs_write_inode(fs, qf_ino, &inode);
132*6a54128fSAndroid Build Coastguard Worker }
133*6a54128fSAndroid Build Coastguard Worker ext2fs_inode_alloc_stats2(fs, qf_ino, -1, 0);
134*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_ib_dirty(fs);
135*6a54128fSAndroid Build Coastguard Worker
136*6a54128fSAndroid Build Coastguard Worker }
137*6a54128fSAndroid Build Coastguard Worker quota_set_sb_inum(fs, 0, qtype);
138*6a54128fSAndroid Build Coastguard Worker
139*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_super_dirty(fs);
140*6a54128fSAndroid Build Coastguard Worker fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
141*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_write_bitmaps(fs);
142*6a54128fSAndroid Build Coastguard Worker if (retval) {
143*6a54128fSAndroid Build Coastguard Worker log_debug("Couldn't write bitmaps: %s", error_message(retval));
144*6a54128fSAndroid Build Coastguard Worker return retval;
145*6a54128fSAndroid Build Coastguard Worker }
146*6a54128fSAndroid Build Coastguard Worker return 0;
147*6a54128fSAndroid Build Coastguard Worker }
148*6a54128fSAndroid Build Coastguard Worker
write_dquots(dict_t * dict,struct quota_handle * qh)149*6a54128fSAndroid Build Coastguard Worker static void write_dquots(dict_t *dict, struct quota_handle *qh)
150*6a54128fSAndroid Build Coastguard Worker {
151*6a54128fSAndroid Build Coastguard Worker dnode_t *n;
152*6a54128fSAndroid Build Coastguard Worker struct dquot *dq;
153*6a54128fSAndroid Build Coastguard Worker
154*6a54128fSAndroid Build Coastguard Worker for (n = dict_first(dict); n; n = dict_next(dict, n)) {
155*6a54128fSAndroid Build Coastguard Worker dq = dnode_get(n);
156*6a54128fSAndroid Build Coastguard Worker if (dq) {
157*6a54128fSAndroid Build Coastguard Worker print_dquot("write", dq);
158*6a54128fSAndroid Build Coastguard Worker dq->dq_h = qh;
159*6a54128fSAndroid Build Coastguard Worker update_grace_times(dq);
160*6a54128fSAndroid Build Coastguard Worker qh->qh_ops->commit_dquot(dq);
161*6a54128fSAndroid Build Coastguard Worker }
162*6a54128fSAndroid Build Coastguard Worker }
163*6a54128fSAndroid Build Coastguard Worker }
164*6a54128fSAndroid Build Coastguard Worker
quota_write_inode(quota_ctx_t qctx,unsigned int qtype_bits)165*6a54128fSAndroid Build Coastguard Worker errcode_t quota_write_inode(quota_ctx_t qctx, unsigned int qtype_bits)
166*6a54128fSAndroid Build Coastguard Worker {
167*6a54128fSAndroid Build Coastguard Worker int retval = 0;
168*6a54128fSAndroid Build Coastguard Worker enum quota_type qtype;
169*6a54128fSAndroid Build Coastguard Worker dict_t *dict;
170*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs;
171*6a54128fSAndroid Build Coastguard Worker struct quota_handle *h = NULL;
172*6a54128fSAndroid Build Coastguard Worker int fmt = QFMT_VFS_V1;
173*6a54128fSAndroid Build Coastguard Worker
174*6a54128fSAndroid Build Coastguard Worker if (!qctx)
175*6a54128fSAndroid Build Coastguard Worker return 0;
176*6a54128fSAndroid Build Coastguard Worker
177*6a54128fSAndroid Build Coastguard Worker fs = qctx->fs;
178*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_mem(sizeof(struct quota_handle), &h);
179*6a54128fSAndroid Build Coastguard Worker if (retval) {
180*6a54128fSAndroid Build Coastguard Worker log_debug("Unable to allocate quota handle: %s",
181*6a54128fSAndroid Build Coastguard Worker error_message(retval));
182*6a54128fSAndroid Build Coastguard Worker goto out;
183*6a54128fSAndroid Build Coastguard Worker }
184*6a54128fSAndroid Build Coastguard Worker
185*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_read_bitmaps(fs);
186*6a54128fSAndroid Build Coastguard Worker if (retval) {
187*6a54128fSAndroid Build Coastguard Worker log_debug("Couldn't read bitmaps: %s", error_message(retval));
188*6a54128fSAndroid Build Coastguard Worker goto out;
189*6a54128fSAndroid Build Coastguard Worker }
190*6a54128fSAndroid Build Coastguard Worker
191*6a54128fSAndroid Build Coastguard Worker for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
192*6a54128fSAndroid Build Coastguard Worker if (((1 << qtype) & qtype_bits) == 0)
193*6a54128fSAndroid Build Coastguard Worker continue;
194*6a54128fSAndroid Build Coastguard Worker
195*6a54128fSAndroid Build Coastguard Worker dict = qctx->quota_dict[qtype];
196*6a54128fSAndroid Build Coastguard Worker if (!dict)
197*6a54128fSAndroid Build Coastguard Worker continue;
198*6a54128fSAndroid Build Coastguard Worker
199*6a54128fSAndroid Build Coastguard Worker retval = quota_file_create(h, fs, qtype, fmt);
200*6a54128fSAndroid Build Coastguard Worker if (retval) {
201*6a54128fSAndroid Build Coastguard Worker log_debug("Cannot initialize io on quotafile: %s",
202*6a54128fSAndroid Build Coastguard Worker error_message(retval));
203*6a54128fSAndroid Build Coastguard Worker goto out;
204*6a54128fSAndroid Build Coastguard Worker }
205*6a54128fSAndroid Build Coastguard Worker
206*6a54128fSAndroid Build Coastguard Worker write_dquots(dict, h);
207*6a54128fSAndroid Build Coastguard Worker retval = quota_file_close(qctx, h);
208*6a54128fSAndroid Build Coastguard Worker if (retval) {
209*6a54128fSAndroid Build Coastguard Worker log_debug("Cannot finish IO on new quotafile: %s",
210*6a54128fSAndroid Build Coastguard Worker strerror(errno));
211*6a54128fSAndroid Build Coastguard Worker if (h->qh_qf.e2_file)
212*6a54128fSAndroid Build Coastguard Worker ext2fs_file_close(h->qh_qf.e2_file);
213*6a54128fSAndroid Build Coastguard Worker (void) quota_inode_truncate(fs, h->qh_qf.ino);
214*6a54128fSAndroid Build Coastguard Worker goto out;
215*6a54128fSAndroid Build Coastguard Worker }
216*6a54128fSAndroid Build Coastguard Worker
217*6a54128fSAndroid Build Coastguard Worker /* Set quota inode numbers in superblock. */
218*6a54128fSAndroid Build Coastguard Worker quota_set_sb_inum(fs, h->qh_qf.ino, qtype);
219*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_super_dirty(fs);
220*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_bb_dirty(fs);
221*6a54128fSAndroid Build Coastguard Worker fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
222*6a54128fSAndroid Build Coastguard Worker }
223*6a54128fSAndroid Build Coastguard Worker
224*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_write_bitmaps(fs);
225*6a54128fSAndroid Build Coastguard Worker if (retval) {
226*6a54128fSAndroid Build Coastguard Worker log_debug("Couldn't write bitmaps: %s", error_message(retval));
227*6a54128fSAndroid Build Coastguard Worker goto out;
228*6a54128fSAndroid Build Coastguard Worker }
229*6a54128fSAndroid Build Coastguard Worker out:
230*6a54128fSAndroid Build Coastguard Worker if (h)
231*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&h);
232*6a54128fSAndroid Build Coastguard Worker return retval;
233*6a54128fSAndroid Build Coastguard Worker }
234*6a54128fSAndroid Build Coastguard Worker
235*6a54128fSAndroid Build Coastguard Worker /******************************************************************/
236*6a54128fSAndroid Build Coastguard Worker /* Helper functions for computing quota in memory. */
237*6a54128fSAndroid Build Coastguard Worker /******************************************************************/
238*6a54128fSAndroid Build Coastguard Worker
dict_uint_cmp(const void * cmp_ctx EXT2FS_ATTR ((unused)),const void * a,const void * b)239*6a54128fSAndroid Build Coastguard Worker static int dict_uint_cmp(const void *cmp_ctx EXT2FS_ATTR((unused)),
240*6a54128fSAndroid Build Coastguard Worker const void *a, const void *b)
241*6a54128fSAndroid Build Coastguard Worker {
242*6a54128fSAndroid Build Coastguard Worker unsigned int c, d;
243*6a54128fSAndroid Build Coastguard Worker
244*6a54128fSAndroid Build Coastguard Worker c = VOIDPTR_TO_UINT(a);
245*6a54128fSAndroid Build Coastguard Worker d = VOIDPTR_TO_UINT(b);
246*6a54128fSAndroid Build Coastguard Worker
247*6a54128fSAndroid Build Coastguard Worker if (c == d)
248*6a54128fSAndroid Build Coastguard Worker return 0;
249*6a54128fSAndroid Build Coastguard Worker else if (c > d)
250*6a54128fSAndroid Build Coastguard Worker return 1;
251*6a54128fSAndroid Build Coastguard Worker else
252*6a54128fSAndroid Build Coastguard Worker return -1;
253*6a54128fSAndroid Build Coastguard Worker }
254*6a54128fSAndroid Build Coastguard Worker
project_quota_valid(quota_ctx_t qctx)255*6a54128fSAndroid Build Coastguard Worker static inline int project_quota_valid(quota_ctx_t qctx)
256*6a54128fSAndroid Build Coastguard Worker {
257*6a54128fSAndroid Build Coastguard Worker return (EXT2_INODE_SIZE(qctx->fs->super) > EXT2_GOOD_OLD_INODE_SIZE);
258*6a54128fSAndroid Build Coastguard Worker }
259*6a54128fSAndroid Build Coastguard Worker
get_qid(struct ext2_inode_large * inode,enum quota_type qtype)260*6a54128fSAndroid Build Coastguard Worker static inline qid_t get_qid(struct ext2_inode_large *inode, enum quota_type qtype)
261*6a54128fSAndroid Build Coastguard Worker {
262*6a54128fSAndroid Build Coastguard Worker unsigned int inode_size;
263*6a54128fSAndroid Build Coastguard Worker
264*6a54128fSAndroid Build Coastguard Worker switch (qtype) {
265*6a54128fSAndroid Build Coastguard Worker case USRQUOTA:
266*6a54128fSAndroid Build Coastguard Worker return inode_uid(*inode);
267*6a54128fSAndroid Build Coastguard Worker case GRPQUOTA:
268*6a54128fSAndroid Build Coastguard Worker return inode_gid(*inode);
269*6a54128fSAndroid Build Coastguard Worker case PRJQUOTA:
270*6a54128fSAndroid Build Coastguard Worker inode_size = EXT2_GOOD_OLD_INODE_SIZE +
271*6a54128fSAndroid Build Coastguard Worker inode->i_extra_isize;
272*6a54128fSAndroid Build Coastguard Worker if (inode_includes(inode_size, i_projid))
273*6a54128fSAndroid Build Coastguard Worker return inode_projid(*inode);
274*6a54128fSAndroid Build Coastguard Worker return 0;
275*6a54128fSAndroid Build Coastguard Worker default:
276*6a54128fSAndroid Build Coastguard Worker return 0;
277*6a54128fSAndroid Build Coastguard Worker }
278*6a54128fSAndroid Build Coastguard Worker
279*6a54128fSAndroid Build Coastguard Worker return 0;
280*6a54128fSAndroid Build Coastguard Worker }
281*6a54128fSAndroid Build Coastguard Worker
quota_dnode_free(dnode_t * node,void * context EXT2FS_ATTR ((unused)))282*6a54128fSAndroid Build Coastguard Worker static void quota_dnode_free(dnode_t *node,
283*6a54128fSAndroid Build Coastguard Worker void *context EXT2FS_ATTR((unused)))
284*6a54128fSAndroid Build Coastguard Worker {
285*6a54128fSAndroid Build Coastguard Worker void *ptr = node ? dnode_get(node) : 0;
286*6a54128fSAndroid Build Coastguard Worker
287*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&ptr);
288*6a54128fSAndroid Build Coastguard Worker free(node);
289*6a54128fSAndroid Build Coastguard Worker }
290*6a54128fSAndroid Build Coastguard Worker
291*6a54128fSAndroid Build Coastguard Worker /*
292*6a54128fSAndroid Build Coastguard Worker * Set up the quota tracking data structures.
293*6a54128fSAndroid Build Coastguard Worker */
quota_init_context(quota_ctx_t * qctx,ext2_filsys fs,unsigned int qtype_bits)294*6a54128fSAndroid Build Coastguard Worker errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs,
295*6a54128fSAndroid Build Coastguard Worker unsigned int qtype_bits)
296*6a54128fSAndroid Build Coastguard Worker {
297*6a54128fSAndroid Build Coastguard Worker errcode_t err;
298*6a54128fSAndroid Build Coastguard Worker dict_t *dict;
299*6a54128fSAndroid Build Coastguard Worker quota_ctx_t ctx;
300*6a54128fSAndroid Build Coastguard Worker enum quota_type qtype;
301*6a54128fSAndroid Build Coastguard Worker
302*6a54128fSAndroid Build Coastguard Worker err = ext2fs_get_mem(sizeof(struct quota_ctx), &ctx);
303*6a54128fSAndroid Build Coastguard Worker if (err) {
304*6a54128fSAndroid Build Coastguard Worker log_debug("Failed to allocate quota context");
305*6a54128fSAndroid Build Coastguard Worker return err;
306*6a54128fSAndroid Build Coastguard Worker }
307*6a54128fSAndroid Build Coastguard Worker
308*6a54128fSAndroid Build Coastguard Worker memset(ctx, 0, sizeof(struct quota_ctx));
309*6a54128fSAndroid Build Coastguard Worker for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
310*6a54128fSAndroid Build Coastguard Worker ctx->quota_file[qtype] = NULL;
311*6a54128fSAndroid Build Coastguard Worker if (qtype_bits) {
312*6a54128fSAndroid Build Coastguard Worker if (((1 << qtype) & qtype_bits) == 0)
313*6a54128fSAndroid Build Coastguard Worker continue;
314*6a54128fSAndroid Build Coastguard Worker } else {
315*6a54128fSAndroid Build Coastguard Worker if (*quota_sb_inump(fs->super, qtype) == 0)
316*6a54128fSAndroid Build Coastguard Worker continue;
317*6a54128fSAndroid Build Coastguard Worker }
318*6a54128fSAndroid Build Coastguard Worker err = ext2fs_get_mem(sizeof(dict_t), &dict);
319*6a54128fSAndroid Build Coastguard Worker if (err) {
320*6a54128fSAndroid Build Coastguard Worker log_debug("Failed to allocate dictionary");
321*6a54128fSAndroid Build Coastguard Worker quota_release_context(&ctx);
322*6a54128fSAndroid Build Coastguard Worker return err;
323*6a54128fSAndroid Build Coastguard Worker }
324*6a54128fSAndroid Build Coastguard Worker ctx->quota_dict[qtype] = dict;
325*6a54128fSAndroid Build Coastguard Worker dict_init(dict, DICTCOUNT_T_MAX, dict_uint_cmp);
326*6a54128fSAndroid Build Coastguard Worker dict_set_allocator(dict, NULL, quota_dnode_free, NULL);
327*6a54128fSAndroid Build Coastguard Worker }
328*6a54128fSAndroid Build Coastguard Worker
329*6a54128fSAndroid Build Coastguard Worker ctx->fs = fs;
330*6a54128fSAndroid Build Coastguard Worker *qctx = ctx;
331*6a54128fSAndroid Build Coastguard Worker return 0;
332*6a54128fSAndroid Build Coastguard Worker }
333*6a54128fSAndroid Build Coastguard Worker
quota_release_context(quota_ctx_t * qctx)334*6a54128fSAndroid Build Coastguard Worker void quota_release_context(quota_ctx_t *qctx)
335*6a54128fSAndroid Build Coastguard Worker {
336*6a54128fSAndroid Build Coastguard Worker errcode_t err;
337*6a54128fSAndroid Build Coastguard Worker dict_t *dict;
338*6a54128fSAndroid Build Coastguard Worker enum quota_type qtype;
339*6a54128fSAndroid Build Coastguard Worker quota_ctx_t ctx;
340*6a54128fSAndroid Build Coastguard Worker
341*6a54128fSAndroid Build Coastguard Worker if (!qctx)
342*6a54128fSAndroid Build Coastguard Worker return;
343*6a54128fSAndroid Build Coastguard Worker
344*6a54128fSAndroid Build Coastguard Worker ctx = *qctx;
345*6a54128fSAndroid Build Coastguard Worker for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
346*6a54128fSAndroid Build Coastguard Worker dict = ctx->quota_dict[qtype];
347*6a54128fSAndroid Build Coastguard Worker ctx->quota_dict[qtype] = 0;
348*6a54128fSAndroid Build Coastguard Worker if (dict) {
349*6a54128fSAndroid Build Coastguard Worker dict_free_nodes(dict);
350*6a54128fSAndroid Build Coastguard Worker free(dict);
351*6a54128fSAndroid Build Coastguard Worker }
352*6a54128fSAndroid Build Coastguard Worker if (ctx->quota_file[qtype]) {
353*6a54128fSAndroid Build Coastguard Worker err = quota_file_close(ctx, ctx->quota_file[qtype]);
354*6a54128fSAndroid Build Coastguard Worker if (err) {
355*6a54128fSAndroid Build Coastguard Worker log_err("Cannot close quotafile: %s",
356*6a54128fSAndroid Build Coastguard Worker strerror(errno));
357*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&ctx->quota_file[qtype]);
358*6a54128fSAndroid Build Coastguard Worker }
359*6a54128fSAndroid Build Coastguard Worker }
360*6a54128fSAndroid Build Coastguard Worker }
361*6a54128fSAndroid Build Coastguard Worker *qctx = NULL;
362*6a54128fSAndroid Build Coastguard Worker free(ctx);
363*6a54128fSAndroid Build Coastguard Worker }
364*6a54128fSAndroid Build Coastguard Worker
get_dq(dict_t * dict,__u32 key)365*6a54128fSAndroid Build Coastguard Worker static struct dquot *get_dq(dict_t *dict, __u32 key)
366*6a54128fSAndroid Build Coastguard Worker {
367*6a54128fSAndroid Build Coastguard Worker struct dquot *dq;
368*6a54128fSAndroid Build Coastguard Worker dnode_t *n;
369*6a54128fSAndroid Build Coastguard Worker
370*6a54128fSAndroid Build Coastguard Worker n = dict_lookup(dict, UINT_TO_VOIDPTR(key));
371*6a54128fSAndroid Build Coastguard Worker if (n)
372*6a54128fSAndroid Build Coastguard Worker dq = dnode_get(n);
373*6a54128fSAndroid Build Coastguard Worker else {
374*6a54128fSAndroid Build Coastguard Worker if (ext2fs_get_mem(sizeof(struct dquot), &dq)) {
375*6a54128fSAndroid Build Coastguard Worker log_err("Unable to allocate dquot");
376*6a54128fSAndroid Build Coastguard Worker return NULL;
377*6a54128fSAndroid Build Coastguard Worker }
378*6a54128fSAndroid Build Coastguard Worker memset(dq, 0, sizeof(struct dquot));
379*6a54128fSAndroid Build Coastguard Worker dict_alloc_insert(dict, UINT_TO_VOIDPTR(key), dq);
380*6a54128fSAndroid Build Coastguard Worker dq->dq_id = key;
381*6a54128fSAndroid Build Coastguard Worker }
382*6a54128fSAndroid Build Coastguard Worker return dq;
383*6a54128fSAndroid Build Coastguard Worker }
384*6a54128fSAndroid Build Coastguard Worker
385*6a54128fSAndroid Build Coastguard Worker
386*6a54128fSAndroid Build Coastguard Worker /*
387*6a54128fSAndroid Build Coastguard Worker * Called to update the blocks used by a particular inode
388*6a54128fSAndroid Build Coastguard Worker */
quota_data_add(quota_ctx_t qctx,struct ext2_inode_large * inode,ext2_ino_t ino EXT2FS_ATTR ((unused)),qsize_t space)389*6a54128fSAndroid Build Coastguard Worker void quota_data_add(quota_ctx_t qctx, struct ext2_inode_large *inode,
390*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino EXT2FS_ATTR((unused)),
391*6a54128fSAndroid Build Coastguard Worker qsize_t space)
392*6a54128fSAndroid Build Coastguard Worker {
393*6a54128fSAndroid Build Coastguard Worker struct dquot *dq;
394*6a54128fSAndroid Build Coastguard Worker dict_t *dict;
395*6a54128fSAndroid Build Coastguard Worker enum quota_type qtype;
396*6a54128fSAndroid Build Coastguard Worker
397*6a54128fSAndroid Build Coastguard Worker if (!qctx)
398*6a54128fSAndroid Build Coastguard Worker return;
399*6a54128fSAndroid Build Coastguard Worker
400*6a54128fSAndroid Build Coastguard Worker log_debug("ADD_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino,
401*6a54128fSAndroid Build Coastguard Worker inode_uid(*inode),
402*6a54128fSAndroid Build Coastguard Worker inode_gid(*inode), space);
403*6a54128fSAndroid Build Coastguard Worker for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
404*6a54128fSAndroid Build Coastguard Worker if (qtype == PRJQUOTA && !project_quota_valid(qctx))
405*6a54128fSAndroid Build Coastguard Worker continue;
406*6a54128fSAndroid Build Coastguard Worker dict = qctx->quota_dict[qtype];
407*6a54128fSAndroid Build Coastguard Worker if (dict) {
408*6a54128fSAndroid Build Coastguard Worker dq = get_dq(dict, get_qid(inode, qtype));
409*6a54128fSAndroid Build Coastguard Worker if (dq)
410*6a54128fSAndroid Build Coastguard Worker dq->dq_dqb.dqb_curspace += space;
411*6a54128fSAndroid Build Coastguard Worker }
412*6a54128fSAndroid Build Coastguard Worker }
413*6a54128fSAndroid Build Coastguard Worker }
414*6a54128fSAndroid Build Coastguard Worker
415*6a54128fSAndroid Build Coastguard Worker /*
416*6a54128fSAndroid Build Coastguard Worker * Called to remove some blocks used by a particular inode
417*6a54128fSAndroid Build Coastguard Worker */
quota_data_sub(quota_ctx_t qctx,struct ext2_inode_large * inode,ext2_ino_t ino EXT2FS_ATTR ((unused)),qsize_t space)418*6a54128fSAndroid Build Coastguard Worker void quota_data_sub(quota_ctx_t qctx, struct ext2_inode_large *inode,
419*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino EXT2FS_ATTR((unused)),
420*6a54128fSAndroid Build Coastguard Worker qsize_t space)
421*6a54128fSAndroid Build Coastguard Worker {
422*6a54128fSAndroid Build Coastguard Worker struct dquot *dq;
423*6a54128fSAndroid Build Coastguard Worker dict_t *dict;
424*6a54128fSAndroid Build Coastguard Worker enum quota_type qtype;
425*6a54128fSAndroid Build Coastguard Worker
426*6a54128fSAndroid Build Coastguard Worker if (!qctx)
427*6a54128fSAndroid Build Coastguard Worker return;
428*6a54128fSAndroid Build Coastguard Worker
429*6a54128fSAndroid Build Coastguard Worker log_debug("SUB_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino,
430*6a54128fSAndroid Build Coastguard Worker inode_uid(*inode),
431*6a54128fSAndroid Build Coastguard Worker inode_gid(*inode), space);
432*6a54128fSAndroid Build Coastguard Worker for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
433*6a54128fSAndroid Build Coastguard Worker if (qtype == PRJQUOTA && !project_quota_valid(qctx))
434*6a54128fSAndroid Build Coastguard Worker continue;
435*6a54128fSAndroid Build Coastguard Worker dict = qctx->quota_dict[qtype];
436*6a54128fSAndroid Build Coastguard Worker if (dict) {
437*6a54128fSAndroid Build Coastguard Worker dq = get_dq(dict, get_qid(inode, qtype));
438*6a54128fSAndroid Build Coastguard Worker if (dq)
439*6a54128fSAndroid Build Coastguard Worker dq->dq_dqb.dqb_curspace -= space;
440*6a54128fSAndroid Build Coastguard Worker }
441*6a54128fSAndroid Build Coastguard Worker }
442*6a54128fSAndroid Build Coastguard Worker }
443*6a54128fSAndroid Build Coastguard Worker
444*6a54128fSAndroid Build Coastguard Worker /*
445*6a54128fSAndroid Build Coastguard Worker * Called to count the files used by an inode's user/group
446*6a54128fSAndroid Build Coastguard Worker */
quota_data_inodes(quota_ctx_t qctx,struct ext2_inode_large * inode,ext2_ino_t ino EXT2FS_ATTR ((unused)),int adjust)447*6a54128fSAndroid Build Coastguard Worker void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode_large *inode,
448*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino EXT2FS_ATTR((unused)), int adjust)
449*6a54128fSAndroid Build Coastguard Worker {
450*6a54128fSAndroid Build Coastguard Worker struct dquot *dq;
451*6a54128fSAndroid Build Coastguard Worker dict_t *dict;
452*6a54128fSAndroid Build Coastguard Worker enum quota_type qtype;
453*6a54128fSAndroid Build Coastguard Worker
454*6a54128fSAndroid Build Coastguard Worker if (!qctx)
455*6a54128fSAndroid Build Coastguard Worker return;
456*6a54128fSAndroid Build Coastguard Worker
457*6a54128fSAndroid Build Coastguard Worker log_debug("ADJ_INODE: Inode: %u, UID/GID: %u/%u, adjust: %d", ino,
458*6a54128fSAndroid Build Coastguard Worker inode_uid(*inode),
459*6a54128fSAndroid Build Coastguard Worker inode_gid(*inode), adjust);
460*6a54128fSAndroid Build Coastguard Worker for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
461*6a54128fSAndroid Build Coastguard Worker if (qtype == PRJQUOTA && !project_quota_valid(qctx))
462*6a54128fSAndroid Build Coastguard Worker continue;
463*6a54128fSAndroid Build Coastguard Worker dict = qctx->quota_dict[qtype];
464*6a54128fSAndroid Build Coastguard Worker if (dict) {
465*6a54128fSAndroid Build Coastguard Worker dq = get_dq(dict, get_qid(inode, qtype));
466*6a54128fSAndroid Build Coastguard Worker if (dq)
467*6a54128fSAndroid Build Coastguard Worker dq->dq_dqb.dqb_curinodes += adjust;
468*6a54128fSAndroid Build Coastguard Worker }
469*6a54128fSAndroid Build Coastguard Worker }
470*6a54128fSAndroid Build Coastguard Worker }
471*6a54128fSAndroid Build Coastguard Worker
quota_compute_usage(quota_ctx_t qctx)472*6a54128fSAndroid Build Coastguard Worker errcode_t quota_compute_usage(quota_ctx_t qctx)
473*6a54128fSAndroid Build Coastguard Worker {
474*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs;
475*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino;
476*6a54128fSAndroid Build Coastguard Worker errcode_t ret;
477*6a54128fSAndroid Build Coastguard Worker struct ext2_inode_large *inode;
478*6a54128fSAndroid Build Coastguard Worker int inode_size;
479*6a54128fSAndroid Build Coastguard Worker qsize_t space;
480*6a54128fSAndroid Build Coastguard Worker ext2_inode_scan scan;
481*6a54128fSAndroid Build Coastguard Worker
482*6a54128fSAndroid Build Coastguard Worker if (!qctx)
483*6a54128fSAndroid Build Coastguard Worker return 0;
484*6a54128fSAndroid Build Coastguard Worker
485*6a54128fSAndroid Build Coastguard Worker fs = qctx->fs;
486*6a54128fSAndroid Build Coastguard Worker ret = ext2fs_open_inode_scan(fs, 0, &scan);
487*6a54128fSAndroid Build Coastguard Worker if (ret) {
488*6a54128fSAndroid Build Coastguard Worker log_err("while opening inode scan. ret=%ld", ret);
489*6a54128fSAndroid Build Coastguard Worker return ret;
490*6a54128fSAndroid Build Coastguard Worker }
491*6a54128fSAndroid Build Coastguard Worker inode_size = fs->super->s_inode_size;
492*6a54128fSAndroid Build Coastguard Worker inode = malloc(inode_size);
493*6a54128fSAndroid Build Coastguard Worker if (!inode) {
494*6a54128fSAndroid Build Coastguard Worker ext2fs_close_inode_scan(scan);
495*6a54128fSAndroid Build Coastguard Worker return ENOMEM;
496*6a54128fSAndroid Build Coastguard Worker }
497*6a54128fSAndroid Build Coastguard Worker while (1) {
498*6a54128fSAndroid Build Coastguard Worker ret = ext2fs_get_next_inode_full(scan, &ino,
499*6a54128fSAndroid Build Coastguard Worker EXT2_INODE(inode), inode_size);
500*6a54128fSAndroid Build Coastguard Worker if (ret) {
501*6a54128fSAndroid Build Coastguard Worker log_err("while getting next inode. ret=%ld", ret);
502*6a54128fSAndroid Build Coastguard Worker ext2fs_close_inode_scan(scan);
503*6a54128fSAndroid Build Coastguard Worker free(inode);
504*6a54128fSAndroid Build Coastguard Worker return ret;
505*6a54128fSAndroid Build Coastguard Worker }
506*6a54128fSAndroid Build Coastguard Worker if (ino == 0)
507*6a54128fSAndroid Build Coastguard Worker break;
508*6a54128fSAndroid Build Coastguard Worker if (!inode->i_links_count)
509*6a54128fSAndroid Build Coastguard Worker continue;
510*6a54128fSAndroid Build Coastguard Worker if (ino == EXT2_ROOT_INO ||
511*6a54128fSAndroid Build Coastguard Worker (ino >= EXT2_FIRST_INODE(fs->super) &&
512*6a54128fSAndroid Build Coastguard Worker ino != quota_type2inum(PRJQUOTA, fs->super))) {
513*6a54128fSAndroid Build Coastguard Worker space = ext2fs_get_stat_i_blocks(fs,
514*6a54128fSAndroid Build Coastguard Worker EXT2_INODE(inode)) << 9;
515*6a54128fSAndroid Build Coastguard Worker quota_data_add(qctx, inode, ino, space);
516*6a54128fSAndroid Build Coastguard Worker quota_data_inodes(qctx, inode, ino, +1);
517*6a54128fSAndroid Build Coastguard Worker }
518*6a54128fSAndroid Build Coastguard Worker }
519*6a54128fSAndroid Build Coastguard Worker
520*6a54128fSAndroid Build Coastguard Worker ext2fs_close_inode_scan(scan);
521*6a54128fSAndroid Build Coastguard Worker free(inode);
522*6a54128fSAndroid Build Coastguard Worker return 0;
523*6a54128fSAndroid Build Coastguard Worker }
524*6a54128fSAndroid Build Coastguard Worker
525*6a54128fSAndroid Build Coastguard Worker struct scan_dquots_data {
526*6a54128fSAndroid Build Coastguard Worker dict_t *quota_dict;
527*6a54128fSAndroid Build Coastguard Worker int update_limits; /* update limits from disk */
528*6a54128fSAndroid Build Coastguard Worker int update_usage;
529*6a54128fSAndroid Build Coastguard Worker int check_consistency;
530*6a54128fSAndroid Build Coastguard Worker int usage_is_inconsistent;
531*6a54128fSAndroid Build Coastguard Worker };
532*6a54128fSAndroid Build Coastguard Worker
scan_dquots_callback(struct dquot * dquot,void * cb_data)533*6a54128fSAndroid Build Coastguard Worker static int scan_dquots_callback(struct dquot *dquot, void *cb_data)
534*6a54128fSAndroid Build Coastguard Worker {
535*6a54128fSAndroid Build Coastguard Worker struct scan_dquots_data *scan_data = cb_data;
536*6a54128fSAndroid Build Coastguard Worker dict_t *quota_dict = scan_data->quota_dict;
537*6a54128fSAndroid Build Coastguard Worker struct dquot *dq;
538*6a54128fSAndroid Build Coastguard Worker
539*6a54128fSAndroid Build Coastguard Worker dq = get_dq(quota_dict, dquot->dq_id);
540*6a54128fSAndroid Build Coastguard Worker if (!dq)
541*6a54128fSAndroid Build Coastguard Worker return -1;
542*6a54128fSAndroid Build Coastguard Worker dq->dq_id = dquot->dq_id;
543*6a54128fSAndroid Build Coastguard Worker dq->dq_flags |= DQF_SEEN;
544*6a54128fSAndroid Build Coastguard Worker
545*6a54128fSAndroid Build Coastguard Worker print_dquot("mem", dq);
546*6a54128fSAndroid Build Coastguard Worker print_dquot("dsk", dquot);
547*6a54128fSAndroid Build Coastguard Worker
548*6a54128fSAndroid Build Coastguard Worker /* Check if there is inconsistency */
549*6a54128fSAndroid Build Coastguard Worker if (scan_data->check_consistency &&
550*6a54128fSAndroid Build Coastguard Worker (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace ||
551*6a54128fSAndroid Build Coastguard Worker dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes)) {
552*6a54128fSAndroid Build Coastguard Worker scan_data->usage_is_inconsistent = 1;
553*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "[QUOTA WARNING] Usage inconsistent for ID %u:"
554*6a54128fSAndroid Build Coastguard Worker "actual (%lld, %lld) != expected (%lld, %lld)\n",
555*6a54128fSAndroid Build Coastguard Worker dq->dq_id, (long long) dq->dq_dqb.dqb_curspace,
556*6a54128fSAndroid Build Coastguard Worker (long long) dq->dq_dqb.dqb_curinodes,
557*6a54128fSAndroid Build Coastguard Worker (long long) dquot->dq_dqb.dqb_curspace,
558*6a54128fSAndroid Build Coastguard Worker (long long) dquot->dq_dqb.dqb_curinodes);
559*6a54128fSAndroid Build Coastguard Worker }
560*6a54128fSAndroid Build Coastguard Worker
561*6a54128fSAndroid Build Coastguard Worker if (scan_data->update_limits) {
562*6a54128fSAndroid Build Coastguard Worker dq->dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit;
563*6a54128fSAndroid Build Coastguard Worker dq->dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit;
564*6a54128fSAndroid Build Coastguard Worker dq->dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit;
565*6a54128fSAndroid Build Coastguard Worker dq->dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit;
566*6a54128fSAndroid Build Coastguard Worker }
567*6a54128fSAndroid Build Coastguard Worker
568*6a54128fSAndroid Build Coastguard Worker if (scan_data->update_usage) {
569*6a54128fSAndroid Build Coastguard Worker dq->dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace;
570*6a54128fSAndroid Build Coastguard Worker dq->dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes;
571*6a54128fSAndroid Build Coastguard Worker }
572*6a54128fSAndroid Build Coastguard Worker
573*6a54128fSAndroid Build Coastguard Worker return 0;
574*6a54128fSAndroid Build Coastguard Worker }
575*6a54128fSAndroid Build Coastguard Worker
576*6a54128fSAndroid Build Coastguard Worker /*
577*6a54128fSAndroid Build Coastguard Worker * Read quotas from disk and updates the in-memory information determined by
578*6a54128fSAndroid Build Coastguard Worker * 'flags' from the on-disk data.
579*6a54128fSAndroid Build Coastguard Worker */
quota_read_all_dquots(quota_ctx_t qctx,ext2_ino_t qf_ino,enum quota_type qtype,unsigned int flags)580*6a54128fSAndroid Build Coastguard Worker errcode_t quota_read_all_dquots(quota_ctx_t qctx, ext2_ino_t qf_ino,
581*6a54128fSAndroid Build Coastguard Worker enum quota_type qtype, unsigned int flags)
582*6a54128fSAndroid Build Coastguard Worker {
583*6a54128fSAndroid Build Coastguard Worker struct scan_dquots_data scan_data;
584*6a54128fSAndroid Build Coastguard Worker struct quota_handle *qh;
585*6a54128fSAndroid Build Coastguard Worker errcode_t err;
586*6a54128fSAndroid Build Coastguard Worker
587*6a54128fSAndroid Build Coastguard Worker if (!qctx)
588*6a54128fSAndroid Build Coastguard Worker return 0;
589*6a54128fSAndroid Build Coastguard Worker
590*6a54128fSAndroid Build Coastguard Worker err = ext2fs_get_mem(sizeof(struct quota_handle), &qh);
591*6a54128fSAndroid Build Coastguard Worker if (err) {
592*6a54128fSAndroid Build Coastguard Worker log_debug("Unable to allocate quota handle");
593*6a54128fSAndroid Build Coastguard Worker return err;
594*6a54128fSAndroid Build Coastguard Worker }
595*6a54128fSAndroid Build Coastguard Worker
596*6a54128fSAndroid Build Coastguard Worker err = quota_file_open(qctx, qh, qf_ino, qtype, -1, 0);
597*6a54128fSAndroid Build Coastguard Worker if (err) {
598*6a54128fSAndroid Build Coastguard Worker log_debug("Open quota file failed");
599*6a54128fSAndroid Build Coastguard Worker goto out;
600*6a54128fSAndroid Build Coastguard Worker }
601*6a54128fSAndroid Build Coastguard Worker
602*6a54128fSAndroid Build Coastguard Worker scan_data.quota_dict = qctx->quota_dict[qh->qh_type];
603*6a54128fSAndroid Build Coastguard Worker scan_data.check_consistency = 0;
604*6a54128fSAndroid Build Coastguard Worker scan_data.update_limits = !!(flags & QREAD_LIMITS);
605*6a54128fSAndroid Build Coastguard Worker scan_data.update_usage = !!(flags & QREAD_USAGE);
606*6a54128fSAndroid Build Coastguard Worker qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data);
607*6a54128fSAndroid Build Coastguard Worker
608*6a54128fSAndroid Build Coastguard Worker err = quota_file_close(qctx, qh);
609*6a54128fSAndroid Build Coastguard Worker if (err) {
610*6a54128fSAndroid Build Coastguard Worker log_debug("Cannot finish IO on new quotafile: %s",
611*6a54128fSAndroid Build Coastguard Worker strerror(errno));
612*6a54128fSAndroid Build Coastguard Worker if (qh->qh_qf.e2_file)
613*6a54128fSAndroid Build Coastguard Worker ext2fs_file_close(qh->qh_qf.e2_file);
614*6a54128fSAndroid Build Coastguard Worker }
615*6a54128fSAndroid Build Coastguard Worker out:
616*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&qh);
617*6a54128fSAndroid Build Coastguard Worker return err;
618*6a54128fSAndroid Build Coastguard Worker }
619*6a54128fSAndroid Build Coastguard Worker
620*6a54128fSAndroid Build Coastguard Worker /*
621*6a54128fSAndroid Build Coastguard Worker * Compares the measured quota in qctx->quota_dict with that in the quota inode
622*6a54128fSAndroid Build Coastguard Worker * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is
623*6a54128fSAndroid Build Coastguard Worker * set to 1 if the supplied and on-disk quota usage values are not identical.
624*6a54128fSAndroid Build Coastguard Worker */
quota_compare_and_update(quota_ctx_t qctx,enum quota_type qtype,int * usage_inconsistent)625*6a54128fSAndroid Build Coastguard Worker errcode_t quota_compare_and_update(quota_ctx_t qctx, enum quota_type qtype,
626*6a54128fSAndroid Build Coastguard Worker int *usage_inconsistent)
627*6a54128fSAndroid Build Coastguard Worker {
628*6a54128fSAndroid Build Coastguard Worker struct quota_handle qh;
629*6a54128fSAndroid Build Coastguard Worker struct scan_dquots_data scan_data;
630*6a54128fSAndroid Build Coastguard Worker struct dquot *dq;
631*6a54128fSAndroid Build Coastguard Worker dnode_t *n;
632*6a54128fSAndroid Build Coastguard Worker dict_t *dict = qctx->quota_dict[qtype];
633*6a54128fSAndroid Build Coastguard Worker errcode_t err = 0;
634*6a54128fSAndroid Build Coastguard Worker
635*6a54128fSAndroid Build Coastguard Worker if (!dict)
636*6a54128fSAndroid Build Coastguard Worker goto out;
637*6a54128fSAndroid Build Coastguard Worker
638*6a54128fSAndroid Build Coastguard Worker err = quota_file_open(qctx, &qh, 0, qtype, -1, 0);
639*6a54128fSAndroid Build Coastguard Worker if (err) {
640*6a54128fSAndroid Build Coastguard Worker log_debug("Open quota file failed");
641*6a54128fSAndroid Build Coastguard Worker goto out;
642*6a54128fSAndroid Build Coastguard Worker }
643*6a54128fSAndroid Build Coastguard Worker
644*6a54128fSAndroid Build Coastguard Worker scan_data.quota_dict = qctx->quota_dict[qtype];
645*6a54128fSAndroid Build Coastguard Worker scan_data.update_limits = 1;
646*6a54128fSAndroid Build Coastguard Worker scan_data.update_usage = 0;
647*6a54128fSAndroid Build Coastguard Worker scan_data.check_consistency = 1;
648*6a54128fSAndroid Build Coastguard Worker scan_data.usage_is_inconsistent = 0;
649*6a54128fSAndroid Build Coastguard Worker err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data);
650*6a54128fSAndroid Build Coastguard Worker if (err) {
651*6a54128fSAndroid Build Coastguard Worker log_debug("Error scanning dquots");
652*6a54128fSAndroid Build Coastguard Worker *usage_inconsistent = 1;
653*6a54128fSAndroid Build Coastguard Worker goto out_close_qh;
654*6a54128fSAndroid Build Coastguard Worker }
655*6a54128fSAndroid Build Coastguard Worker
656*6a54128fSAndroid Build Coastguard Worker for (n = dict_first(dict); n; n = dict_next(dict, n)) {
657*6a54128fSAndroid Build Coastguard Worker dq = dnode_get(n);
658*6a54128fSAndroid Build Coastguard Worker if (!dq)
659*6a54128fSAndroid Build Coastguard Worker continue;
660*6a54128fSAndroid Build Coastguard Worker if ((dq->dq_flags & DQF_SEEN) == 0) {
661*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "[QUOTA WARNING] "
662*6a54128fSAndroid Build Coastguard Worker "Missing quota entry ID %d\n", dq->dq_id);
663*6a54128fSAndroid Build Coastguard Worker scan_data.usage_is_inconsistent = 1;
664*6a54128fSAndroid Build Coastguard Worker }
665*6a54128fSAndroid Build Coastguard Worker }
666*6a54128fSAndroid Build Coastguard Worker *usage_inconsistent = scan_data.usage_is_inconsistent;
667*6a54128fSAndroid Build Coastguard Worker
668*6a54128fSAndroid Build Coastguard Worker out_close_qh:
669*6a54128fSAndroid Build Coastguard Worker err = quota_file_close(qctx, &qh);
670*6a54128fSAndroid Build Coastguard Worker if (err) {
671*6a54128fSAndroid Build Coastguard Worker log_debug("Cannot close quotafile: %s", error_message(errno));
672*6a54128fSAndroid Build Coastguard Worker if (qh.qh_qf.e2_file)
673*6a54128fSAndroid Build Coastguard Worker ext2fs_file_close(qh.qh_qf.e2_file);
674*6a54128fSAndroid Build Coastguard Worker }
675*6a54128fSAndroid Build Coastguard Worker out:
676*6a54128fSAndroid Build Coastguard Worker return err;
677*6a54128fSAndroid Build Coastguard Worker }
678*6a54128fSAndroid Build Coastguard Worker
parse_quota_opts(const char * opts,int (* func)(char *))679*6a54128fSAndroid Build Coastguard Worker int parse_quota_opts(const char *opts, int (*func)(char *))
680*6a54128fSAndroid Build Coastguard Worker {
681*6a54128fSAndroid Build Coastguard Worker char *buf, *token, *next, *p;
682*6a54128fSAndroid Build Coastguard Worker int len;
683*6a54128fSAndroid Build Coastguard Worker int ret = 0;
684*6a54128fSAndroid Build Coastguard Worker
685*6a54128fSAndroid Build Coastguard Worker len = strlen(opts);
686*6a54128fSAndroid Build Coastguard Worker buf = malloc(len + 1);
687*6a54128fSAndroid Build Coastguard Worker if (!buf) {
688*6a54128fSAndroid Build Coastguard Worker fprintf(stderr,
689*6a54128fSAndroid Build Coastguard Worker "Couldn't allocate memory to parse quota options!\n");
690*6a54128fSAndroid Build Coastguard Worker return -ENOMEM;
691*6a54128fSAndroid Build Coastguard Worker }
692*6a54128fSAndroid Build Coastguard Worker strcpy(buf, opts);
693*6a54128fSAndroid Build Coastguard Worker for (token = buf; token && *token; token = next) {
694*6a54128fSAndroid Build Coastguard Worker p = strchr(token, ',');
695*6a54128fSAndroid Build Coastguard Worker next = 0;
696*6a54128fSAndroid Build Coastguard Worker if (p) {
697*6a54128fSAndroid Build Coastguard Worker *p = 0;
698*6a54128fSAndroid Build Coastguard Worker next = p + 1;
699*6a54128fSAndroid Build Coastguard Worker }
700*6a54128fSAndroid Build Coastguard Worker ret = func(token);
701*6a54128fSAndroid Build Coastguard Worker if (ret)
702*6a54128fSAndroid Build Coastguard Worker break;
703*6a54128fSAndroid Build Coastguard Worker }
704*6a54128fSAndroid Build Coastguard Worker free(buf);
705*6a54128fSAndroid Build Coastguard Worker return ret;
706*6a54128fSAndroid Build Coastguard Worker }
707