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 = "afile_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 = "afile_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