1*59bfda1fSAndroid Build Coastguard Worker /** quotaio.c
2*59bfda1fSAndroid Build Coastguard Worker *
3*59bfda1fSAndroid Build Coastguard Worker * Generic IO operations on quotafiles
4*59bfda1fSAndroid Build Coastguard Worker * Jan Kara <[email protected]> - sponsored by SuSE CR
5*59bfda1fSAndroid Build Coastguard Worker * Aditya Kali <[email protected]> - Ported to e2fsprogs
6*59bfda1fSAndroid Build Coastguard Worker * Hyojun Kim <[email protected]> - Ported to f2fs-tools
7*59bfda1fSAndroid Build Coastguard Worker */
8*59bfda1fSAndroid Build Coastguard Worker
9*59bfda1fSAndroid Build Coastguard Worker #include <stdio.h>
10*59bfda1fSAndroid Build Coastguard Worker #include <errno.h>
11*59bfda1fSAndroid Build Coastguard Worker #include <string.h>
12*59bfda1fSAndroid Build Coastguard Worker #include <unistd.h>
13*59bfda1fSAndroid Build Coastguard Worker #include <stdlib.h>
14*59bfda1fSAndroid Build Coastguard Worker #include <time.h>
15*59bfda1fSAndroid Build Coastguard Worker #include <sys/types.h>
16*59bfda1fSAndroid Build Coastguard Worker #include <sys/stat.h>
17*59bfda1fSAndroid Build Coastguard Worker #include <sys/file.h>
18*59bfda1fSAndroid Build Coastguard Worker #include <assert.h>
19*59bfda1fSAndroid Build Coastguard Worker
20*59bfda1fSAndroid Build Coastguard Worker #include "common.h"
21*59bfda1fSAndroid Build Coastguard Worker #include "quotaio.h"
22*59bfda1fSAndroid Build Coastguard Worker
23*59bfda1fSAndroid Build Coastguard Worker static const char * const extensions[MAXQUOTAS] = {
24*59bfda1fSAndroid Build Coastguard Worker [USRQUOTA] = "user",
25*59bfda1fSAndroid Build Coastguard Worker [GRPQUOTA] = "group",
26*59bfda1fSAndroid Build Coastguard Worker [PRJQUOTA] = "project",
27*59bfda1fSAndroid Build Coastguard Worker };
28*59bfda1fSAndroid Build Coastguard Worker
29*59bfda1fSAndroid Build Coastguard Worker /* Header in all newer quotafiles */
30*59bfda1fSAndroid Build Coastguard Worker struct disk_dqheader {
31*59bfda1fSAndroid Build Coastguard Worker __le32 dqh_magic;
32*59bfda1fSAndroid Build Coastguard Worker __le32 dqh_version;
33*59bfda1fSAndroid Build Coastguard Worker };
34*59bfda1fSAndroid Build Coastguard Worker
35*59bfda1fSAndroid Build Coastguard Worker static_assert(sizeof(struct disk_dqheader) == 8, "");
36*59bfda1fSAndroid Build Coastguard Worker
37*59bfda1fSAndroid Build Coastguard Worker int cur_qtype = -1;
38*59bfda1fSAndroid Build Coastguard Worker u32 qf_last_blkofs[MAXQUOTAS] = {0, 0, 0};
39*59bfda1fSAndroid Build Coastguard Worker enum qf_szchk_type_t qf_szchk_type[MAXQUOTAS] =
40*59bfda1fSAndroid Build Coastguard Worker {
41*59bfda1fSAndroid Build Coastguard Worker QF_SZCHK_NONE, QF_SZCHK_NONE, QF_SZCHK_NONE
42*59bfda1fSAndroid Build Coastguard Worker };
43*59bfda1fSAndroid Build Coastguard Worker u64 qf_maxsize[MAXQUOTAS];
44*59bfda1fSAndroid Build Coastguard Worker
45*59bfda1fSAndroid Build Coastguard Worker /**
46*59bfda1fSAndroid Build Coastguard Worker * Convert type of quota to written representation
47*59bfda1fSAndroid Build Coastguard Worker */
quota_type2name(enum quota_type qtype)48*59bfda1fSAndroid Build Coastguard Worker const char *quota_type2name(enum quota_type qtype)
49*59bfda1fSAndroid Build Coastguard Worker {
50*59bfda1fSAndroid Build Coastguard Worker if (qtype >= MAXQUOTAS)
51*59bfda1fSAndroid Build Coastguard Worker return "unknown";
52*59bfda1fSAndroid Build Coastguard Worker return extensions[qtype];
53*59bfda1fSAndroid Build Coastguard Worker }
54*59bfda1fSAndroid Build Coastguard Worker
55*59bfda1fSAndroid Build Coastguard Worker /*
56*59bfda1fSAndroid Build Coastguard Worker * Set grace time if needed
57*59bfda1fSAndroid Build Coastguard Worker */
update_grace_times(struct dquot * q)58*59bfda1fSAndroid Build Coastguard Worker void update_grace_times(struct dquot *q)
59*59bfda1fSAndroid Build Coastguard Worker {
60*59bfda1fSAndroid Build Coastguard Worker time_t now;
61*59bfda1fSAndroid Build Coastguard Worker
62*59bfda1fSAndroid Build Coastguard Worker time(&now);
63*59bfda1fSAndroid Build Coastguard Worker if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) >
64*59bfda1fSAndroid Build Coastguard Worker q->dq_dqb.dqb_bsoftlimit) {
65*59bfda1fSAndroid Build Coastguard Worker if (!q->dq_dqb.dqb_btime)
66*59bfda1fSAndroid Build Coastguard Worker q->dq_dqb.dqb_btime =
67*59bfda1fSAndroid Build Coastguard Worker now + q->dq_h->qh_info.dqi_bgrace;
68*59bfda1fSAndroid Build Coastguard Worker } else {
69*59bfda1fSAndroid Build Coastguard Worker q->dq_dqb.dqb_btime = 0;
70*59bfda1fSAndroid Build Coastguard Worker }
71*59bfda1fSAndroid Build Coastguard Worker
72*59bfda1fSAndroid Build Coastguard Worker if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes >
73*59bfda1fSAndroid Build Coastguard Worker q->dq_dqb.dqb_isoftlimit) {
74*59bfda1fSAndroid Build Coastguard Worker if (!q->dq_dqb.dqb_itime)
75*59bfda1fSAndroid Build Coastguard Worker q->dq_dqb.dqb_itime =
76*59bfda1fSAndroid Build Coastguard Worker now + q->dq_h->qh_info.dqi_igrace;
77*59bfda1fSAndroid Build Coastguard Worker } else {
78*59bfda1fSAndroid Build Coastguard Worker q->dq_dqb.dqb_itime = 0;
79*59bfda1fSAndroid Build Coastguard Worker }
80*59bfda1fSAndroid Build Coastguard Worker }
81*59bfda1fSAndroid Build Coastguard Worker
82*59bfda1fSAndroid Build Coastguard Worker /* Functions to read/write quota file. */
quota_write_nomount(struct quota_file * qf,long offset,void * buf,unsigned int size)83*59bfda1fSAndroid Build Coastguard Worker static unsigned int quota_write_nomount(struct quota_file *qf,
84*59bfda1fSAndroid Build Coastguard Worker long offset,
85*59bfda1fSAndroid Build Coastguard Worker void *buf, unsigned int size)
86*59bfda1fSAndroid Build Coastguard Worker {
87*59bfda1fSAndroid Build Coastguard Worker unsigned int written;
88*59bfda1fSAndroid Build Coastguard Worker
89*59bfda1fSAndroid Build Coastguard Worker written = f2fs_write(qf->sbi, qf->ino, buf, size, offset);
90*59bfda1fSAndroid Build Coastguard Worker if (qf->filesize < offset + written)
91*59bfda1fSAndroid Build Coastguard Worker qf->filesize = offset + written;
92*59bfda1fSAndroid Build Coastguard Worker if (written != size)
93*59bfda1fSAndroid Build Coastguard Worker return -EIO;
94*59bfda1fSAndroid Build Coastguard Worker return written;
95*59bfda1fSAndroid Build Coastguard Worker }
96*59bfda1fSAndroid Build Coastguard Worker
quota_read_nomount(struct quota_file * qf,long offset,void * buf,unsigned int size)97*59bfda1fSAndroid Build Coastguard Worker static unsigned int quota_read_nomount(struct quota_file *qf, long offset,
98*59bfda1fSAndroid Build Coastguard Worker void *buf, unsigned int size)
99*59bfda1fSAndroid Build Coastguard Worker {
100*59bfda1fSAndroid Build Coastguard Worker return f2fs_read(qf->sbi, qf->ino, buf, size, offset);
101*59bfda1fSAndroid Build Coastguard Worker }
102*59bfda1fSAndroid Build Coastguard Worker
103*59bfda1fSAndroid Build Coastguard Worker /*
104*59bfda1fSAndroid Build Coastguard Worker * Detect quota format and initialize quota IO
105*59bfda1fSAndroid Build Coastguard Worker */
quota_file_open(struct f2fs_sb_info * sbi,struct quota_handle * h,enum quota_type qtype,int flags)106*59bfda1fSAndroid Build Coastguard Worker errcode_t quota_file_open(struct f2fs_sb_info *sbi, struct quota_handle *h,
107*59bfda1fSAndroid Build Coastguard Worker enum quota_type qtype, int flags)
108*59bfda1fSAndroid Build Coastguard Worker {
109*59bfda1fSAndroid Build Coastguard Worker struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
110*59bfda1fSAndroid Build Coastguard Worker struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
111*59bfda1fSAndroid Build Coastguard Worker quota_ctx_t qctx = fsck->qctx;
112*59bfda1fSAndroid Build Coastguard Worker f2fs_ino_t qf_ino;
113*59bfda1fSAndroid Build Coastguard Worker errcode_t err = 0;
114*59bfda1fSAndroid Build Coastguard Worker int allocated_handle = 0;
115*59bfda1fSAndroid Build Coastguard Worker
116*59bfda1fSAndroid Build Coastguard Worker if (qtype >= MAXQUOTAS)
117*59bfda1fSAndroid Build Coastguard Worker return EINVAL;
118*59bfda1fSAndroid Build Coastguard Worker
119*59bfda1fSAndroid Build Coastguard Worker qf_ino = sb->qf_ino[qtype];
120*59bfda1fSAndroid Build Coastguard Worker
121*59bfda1fSAndroid Build Coastguard Worker if (!h) {
122*59bfda1fSAndroid Build Coastguard Worker if (qctx->quota_file[qtype]) {
123*59bfda1fSAndroid Build Coastguard Worker h = qctx->quota_file[qtype];
124*59bfda1fSAndroid Build Coastguard Worker (void) quota_file_close(sbi, h, 0);
125*59bfda1fSAndroid Build Coastguard Worker }
126*59bfda1fSAndroid Build Coastguard Worker err = quota_get_mem(sizeof(struct quota_handle), &h);
127*59bfda1fSAndroid Build Coastguard Worker if (err) {
128*59bfda1fSAndroid Build Coastguard Worker log_err("Unable to allocate quota handle");
129*59bfda1fSAndroid Build Coastguard Worker return err;
130*59bfda1fSAndroid Build Coastguard Worker }
131*59bfda1fSAndroid Build Coastguard Worker allocated_handle = 1;
132*59bfda1fSAndroid Build Coastguard Worker }
133*59bfda1fSAndroid Build Coastguard Worker
134*59bfda1fSAndroid Build Coastguard Worker h->qh_qf.sbi = sbi;
135*59bfda1fSAndroid Build Coastguard Worker h->qh_qf.ino = qf_ino;
136*59bfda1fSAndroid Build Coastguard Worker h->write = quota_write_nomount;
137*59bfda1fSAndroid Build Coastguard Worker h->read = quota_read_nomount;
138*59bfda1fSAndroid Build Coastguard Worker h->qh_file_flags = flags;
139*59bfda1fSAndroid Build Coastguard Worker h->qh_io_flags = 0;
140*59bfda1fSAndroid Build Coastguard Worker h->qh_type = qtype;
141*59bfda1fSAndroid Build Coastguard Worker h->qh_fmt = QFMT_VFS_V1;
142*59bfda1fSAndroid Build Coastguard Worker memset(&h->qh_info, 0, sizeof(h->qh_info));
143*59bfda1fSAndroid Build Coastguard Worker h->qh_ops = "afile_ops_2;
144*59bfda1fSAndroid Build Coastguard Worker
145*59bfda1fSAndroid Build Coastguard Worker if (h->qh_ops->check_file &&
146*59bfda1fSAndroid Build Coastguard Worker (h->qh_ops->check_file(h, qtype) == 0)) {
147*59bfda1fSAndroid Build Coastguard Worker log_err("qh_ops->check_file failed");
148*59bfda1fSAndroid Build Coastguard Worker err = EIO;
149*59bfda1fSAndroid Build Coastguard Worker goto errout;
150*59bfda1fSAndroid Build Coastguard Worker }
151*59bfda1fSAndroid Build Coastguard Worker
152*59bfda1fSAndroid Build Coastguard Worker if (h->qh_ops->init_io && (h->qh_ops->init_io(h, qtype) < 0)) {
153*59bfda1fSAndroid Build Coastguard Worker log_err("qh_ops->init_io failed");
154*59bfda1fSAndroid Build Coastguard Worker err = EIO;
155*59bfda1fSAndroid Build Coastguard Worker goto errout;
156*59bfda1fSAndroid Build Coastguard Worker }
157*59bfda1fSAndroid Build Coastguard Worker if (allocated_handle)
158*59bfda1fSAndroid Build Coastguard Worker qctx->quota_file[qtype] = h;
159*59bfda1fSAndroid Build Coastguard Worker errout:
160*59bfda1fSAndroid Build Coastguard Worker return err;
161*59bfda1fSAndroid Build Coastguard Worker }
162*59bfda1fSAndroid Build Coastguard Worker
163*59bfda1fSAndroid Build Coastguard Worker /*
164*59bfda1fSAndroid Build Coastguard Worker * Create new quotafile of specified format on given filesystem
165*59bfda1fSAndroid Build Coastguard Worker */
quota_file_create(struct f2fs_sb_info * sbi,struct quota_handle * h,enum quota_type qtype)166*59bfda1fSAndroid Build Coastguard Worker errcode_t quota_file_create(struct f2fs_sb_info *sbi, struct quota_handle *h,
167*59bfda1fSAndroid Build Coastguard Worker enum quota_type qtype)
168*59bfda1fSAndroid Build Coastguard Worker {
169*59bfda1fSAndroid Build Coastguard Worker struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
170*59bfda1fSAndroid Build Coastguard Worker f2fs_ino_t qf_inum = sb->qf_ino[qtype];
171*59bfda1fSAndroid Build Coastguard Worker errcode_t err = 0;
172*59bfda1fSAndroid Build Coastguard Worker
173*59bfda1fSAndroid Build Coastguard Worker memset(&h->qh_qf, 0, sizeof(h->qh_qf));
174*59bfda1fSAndroid Build Coastguard Worker h->qh_qf.sbi = sbi;
175*59bfda1fSAndroid Build Coastguard Worker h->qh_qf.ino = qf_inum;
176*59bfda1fSAndroid Build Coastguard Worker h->write = quota_write_nomount;
177*59bfda1fSAndroid Build Coastguard Worker h->read = quota_read_nomount;
178*59bfda1fSAndroid Build Coastguard Worker
179*59bfda1fSAndroid Build Coastguard Worker log_debug("Creating quota ino=%u, type=%d", qf_inum, qtype);
180*59bfda1fSAndroid Build Coastguard Worker h->qh_io_flags = 0;
181*59bfda1fSAndroid Build Coastguard Worker h->qh_type = qtype;
182*59bfda1fSAndroid Build Coastguard Worker h->qh_fmt = QFMT_VFS_V1;
183*59bfda1fSAndroid Build Coastguard Worker memset(&h->qh_info, 0, sizeof(h->qh_info));
184*59bfda1fSAndroid Build Coastguard Worker h->qh_ops = "afile_ops_2;
185*59bfda1fSAndroid Build Coastguard Worker
186*59bfda1fSAndroid Build Coastguard Worker if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) {
187*59bfda1fSAndroid Build Coastguard Worker log_err("qh_ops->new_io failed");
188*59bfda1fSAndroid Build Coastguard Worker err = EIO;
189*59bfda1fSAndroid Build Coastguard Worker }
190*59bfda1fSAndroid Build Coastguard Worker
191*59bfda1fSAndroid Build Coastguard Worker return err;
192*59bfda1fSAndroid Build Coastguard Worker }
193*59bfda1fSAndroid Build Coastguard Worker
194*59bfda1fSAndroid Build Coastguard Worker /*
195*59bfda1fSAndroid Build Coastguard Worker * Close quotafile and release handle
196*59bfda1fSAndroid Build Coastguard Worker */
quota_file_close(struct f2fs_sb_info * sbi,struct quota_handle * h,int update_filesize)197*59bfda1fSAndroid Build Coastguard Worker errcode_t quota_file_close(struct f2fs_sb_info *sbi, struct quota_handle *h,
198*59bfda1fSAndroid Build Coastguard Worker int update_filesize)
199*59bfda1fSAndroid Build Coastguard Worker {
200*59bfda1fSAndroid Build Coastguard Worker struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
201*59bfda1fSAndroid Build Coastguard Worker quota_ctx_t qctx = fsck->qctx;
202*59bfda1fSAndroid Build Coastguard Worker
203*59bfda1fSAndroid Build Coastguard Worker if (h->qh_io_flags & IOFL_INFODIRTY) {
204*59bfda1fSAndroid Build Coastguard Worker if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0)
205*59bfda1fSAndroid Build Coastguard Worker return EIO;
206*59bfda1fSAndroid Build Coastguard Worker h->qh_io_flags &= ~IOFL_INFODIRTY;
207*59bfda1fSAndroid Build Coastguard Worker }
208*59bfda1fSAndroid Build Coastguard Worker if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0)
209*59bfda1fSAndroid Build Coastguard Worker return EIO;
210*59bfda1fSAndroid Build Coastguard Worker if (update_filesize) {
211*59bfda1fSAndroid Build Coastguard Worker f2fs_filesize_update(sbi, h->qh_qf.ino, h->qh_qf.filesize);
212*59bfda1fSAndroid Build Coastguard Worker }
213*59bfda1fSAndroid Build Coastguard Worker if (qctx->quota_file[h->qh_type] == h)
214*59bfda1fSAndroid Build Coastguard Worker quota_free_mem(&qctx->quota_file[h->qh_type]);
215*59bfda1fSAndroid Build Coastguard Worker return 0;
216*59bfda1fSAndroid Build Coastguard Worker }
217*59bfda1fSAndroid Build Coastguard Worker
218*59bfda1fSAndroid Build Coastguard Worker /*
219*59bfda1fSAndroid Build Coastguard Worker * Create empty quota structure
220*59bfda1fSAndroid Build Coastguard Worker */
get_empty_dquot(void)221*59bfda1fSAndroid Build Coastguard Worker struct dquot *get_empty_dquot(void)
222*59bfda1fSAndroid Build Coastguard Worker {
223*59bfda1fSAndroid Build Coastguard Worker struct dquot *dquot;
224*59bfda1fSAndroid Build Coastguard Worker
225*59bfda1fSAndroid Build Coastguard Worker if (quota_get_memzero(sizeof(struct dquot), &dquot)) {
226*59bfda1fSAndroid Build Coastguard Worker log_err("Failed to allocate dquot");
227*59bfda1fSAndroid Build Coastguard Worker return NULL;
228*59bfda1fSAndroid Build Coastguard Worker }
229*59bfda1fSAndroid Build Coastguard Worker
230*59bfda1fSAndroid Build Coastguard Worker dquot->dq_id = -1;
231*59bfda1fSAndroid Build Coastguard Worker return dquot;
232*59bfda1fSAndroid Build Coastguard Worker }
233