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