xref: /aosp_15_r20/external/f2fs-tools/fsck/quotaio.c (revision 59bfda1f02d633cd6b8b69f31eee485d40f6eef6)
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 = &quotafile_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 = &quotafile_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