1 /* 2 * Implementation of new quotafile format 3 * 4 * Jan Kara <jack (at) suse.cz> - sponsored by SuSE CR 5 */ 6 7 #include <sys/types.h> 8 #include <errno.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <unistd.h> 13 14 #include "common.h" 15 #include "quotaio_v2.h" 16 #include "dqblk_v2.h" 17 #include "quotaio.h" 18 #include "quotaio_tree.h" 19 20 static int v2_check_file(struct quota_handle *h, int type, int fmt); 21 static int v2_init_io(struct quota_handle *h); 22 static int v2_new_io(struct quota_handle *h); 23 static int v2_write_info(struct quota_handle *h); 24 static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id); 25 static int v2_commit_dquot(struct dquot *dquot); 26 static int v2_scan_dquots(struct quota_handle *h, 27 int (*process_dquot) (struct dquot *dquot, 28 void *data), 29 void *data); 30 static int v2_report(struct quota_handle *h, int verbose); 31 32 struct quotafile_ops quotafile_ops_2 = { 33 .check_file = v2_check_file, 34 .init_io = v2_init_io, 35 .new_io = v2_new_io, 36 .write_info = v2_write_info, 37 .read_dquot = v2_read_dquot, 38 .commit_dquot = v2_commit_dquot, 39 .scan_dquots = v2_scan_dquots, 40 .report = v2_report, 41 }; 42 43 /* 44 * Copy dquot from disk to memory 45 */ 46 static void v2r1_disk2memdqblk(struct dquot *dquot, void *dp) 47 { 48 struct util_dqblk *m = &dquot->dq_dqb; 49 struct v2r1_disk_dqblk *d = dp, empty; 50 51 dquot->dq_id = ext2fs_le32_to_cpu(d->dqb_id); 52 m->dqb_ihardlimit = ext2fs_le64_to_cpu(d->dqb_ihardlimit); 53 m->dqb_isoftlimit = ext2fs_le64_to_cpu(d->dqb_isoftlimit); 54 m->dqb_bhardlimit = ext2fs_le64_to_cpu(d->dqb_bhardlimit); 55 m->dqb_bsoftlimit = ext2fs_le64_to_cpu(d->dqb_bsoftlimit); 56 m->dqb_curinodes = ext2fs_le64_to_cpu(d->dqb_curinodes); 57 m->dqb_curspace = ext2fs_le64_to_cpu(d->dqb_curspace); 58 m->dqb_itime = ext2fs_le64_to_cpu(d->dqb_itime); 59 m->dqb_btime = ext2fs_le64_to_cpu(d->dqb_btime); 60 61 memset(&empty, 0, sizeof(struct v2r1_disk_dqblk)); 62 empty.dqb_itime = ext2fs_cpu_to_le64(1); 63 if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk))) 64 m->dqb_itime = 0; 65 } 66 67 /* 68 * Copy dquot from memory to disk 69 */ 70 static void v2r1_mem2diskdqblk(void *dp, struct dquot *dquot) 71 { 72 struct util_dqblk *m = &dquot->dq_dqb; 73 struct v2r1_disk_dqblk *d = dp; 74 75 d->dqb_ihardlimit = ext2fs_cpu_to_le64(m->dqb_ihardlimit); 76 d->dqb_isoftlimit = ext2fs_cpu_to_le64(m->dqb_isoftlimit); 77 d->dqb_bhardlimit = ext2fs_cpu_to_le64(m->dqb_bhardlimit); 78 d->dqb_bsoftlimit = ext2fs_cpu_to_le64(m->dqb_bsoftlimit); 79 d->dqb_curinodes = ext2fs_cpu_to_le64(m->dqb_curinodes); 80 d->dqb_curspace = ext2fs_cpu_to_le64(m->dqb_curspace); 81 d->dqb_itime = ext2fs_cpu_to_le64(m->dqb_itime); 82 d->dqb_btime = ext2fs_cpu_to_le64(m->dqb_btime); 83 d->dqb_id = ext2fs_cpu_to_le32(dquot->dq_id); 84 if (qtree_entry_unused(&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree, dp)) 85 d->dqb_itime = ext2fs_cpu_to_le64(1); 86 } 87 88 static int v2r1_is_id(void *dp, struct dquot *dquot) 89 { 90 struct v2r1_disk_dqblk *d = dp; 91 struct qtree_mem_dqinfo *info = 92 &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; 93 94 if (qtree_entry_unused(info, dp)) 95 return 0; 96 return ext2fs_le32_to_cpu(d->dqb_id) == dquot->dq_id; 97 } 98 99 static struct qtree_fmt_operations v2r1_fmt_ops = { 100 .mem2disk_dqblk = v2r1_mem2diskdqblk, 101 .disk2mem_dqblk = v2r1_disk2memdqblk, 102 .is_id = v2r1_is_id, 103 }; 104 105 /* 106 * Copy dqinfo from disk to memory 107 */ 108 static inline void v2_disk2memdqinfo(struct util_dqinfo *m, 109 struct v2_disk_dqinfo *d) 110 { 111 m->dqi_bgrace = ext2fs_le32_to_cpu(d->dqi_bgrace); 112 m->dqi_igrace = ext2fs_le32_to_cpu(d->dqi_igrace); 113 m->u.v2_mdqi.dqi_flags = ext2fs_le32_to_cpu(d->dqi_flags) & V2_DQF_MASK; 114 m->u.v2_mdqi.dqi_qtree.dqi_blocks = ext2fs_le32_to_cpu(d->dqi_blocks); 115 m->u.v2_mdqi.dqi_qtree.dqi_free_blk = 116 ext2fs_le32_to_cpu(d->dqi_free_blk); 117 m->u.v2_mdqi.dqi_qtree.dqi_free_entry = 118 ext2fs_le32_to_cpu(d->dqi_free_entry); 119 } 120 121 /* 122 * Copy dqinfo from memory to disk 123 */ 124 static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d, 125 struct util_dqinfo *m) 126 { 127 d->dqi_bgrace = ext2fs_cpu_to_le32(m->dqi_bgrace); 128 d->dqi_igrace = ext2fs_cpu_to_le32(m->dqi_igrace); 129 d->dqi_flags = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_flags & V2_DQF_MASK); 130 d->dqi_blocks = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_blocks); 131 d->dqi_free_blk = 132 ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_blk); 133 d->dqi_free_entry = 134 ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_entry); 135 } 136 137 static int v2_read_header(struct quota_handle *h, struct v2_disk_dqheader *dqh) 138 { 139 if (h->e2fs_read(&h->qh_qf, 0, dqh, sizeof(struct v2_disk_dqheader)) != 140 sizeof(struct v2_disk_dqheader)) 141 return 0; 142 143 return 1; 144 } 145 146 /* 147 * Check whether given quota file is in our format 148 */ 149 static int v2_check_file(struct quota_handle *h, int type, int fmt) 150 { 151 struct v2_disk_dqheader dqh; 152 int file_magics[] = INITQMAGICS; 153 154 if (fmt != QFMT_VFS_V1) 155 return 0; 156 157 if (!v2_read_header(h, &dqh)) 158 return 0; 159 160 if (ext2fs_le32_to_cpu(dqh.dqh_magic) != file_magics[type]) { 161 if (ext2fs_be32_to_cpu(dqh.dqh_magic) == file_magics[type]) 162 log_err("Your quota file is stored in wrong endianity"); 163 return 0; 164 } 165 if (V2_VERSION != ext2fs_le32_to_cpu(dqh.dqh_version)) 166 return 0; 167 return 1; 168 } 169 170 /* 171 * Open quotafile 172 */ 173 static int v2_init_io(struct quota_handle *h) 174 { 175 struct v2_disk_dqinfo ddqinfo; 176 177 h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = 178 sizeof(struct v2r1_disk_dqblk); 179 h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; 180 181 /* Read information about quotafile */ 182 if (h->e2fs_read(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, 183 sizeof(ddqinfo)) != sizeof(ddqinfo)) 184 return -1; 185 v2_disk2memdqinfo(&h->qh_info, &ddqinfo); 186 return 0; 187 } 188 189 /* 190 * Initialize new quotafile 191 */ 192 static int v2_new_io(struct quota_handle *h) 193 { 194 int file_magics[] = INITQMAGICS; 195 struct v2_disk_dqheader ddqheader; 196 struct v2_disk_dqinfo ddqinfo; 197 198 if (h->qh_fmt != QFMT_VFS_V1) 199 return -1; 200 201 /* Write basic quota header */ 202 ddqheader.dqh_magic = ext2fs_cpu_to_le32(file_magics[h->qh_type]); 203 ddqheader.dqh_version = ext2fs_cpu_to_le32(V2_VERSION); 204 if (h->e2fs_write(&h->qh_qf, 0, &ddqheader, sizeof(ddqheader)) != 205 sizeof(ddqheader)) 206 return -1; 207 208 /* Write information about quotafile */ 209 h->qh_info.dqi_bgrace = MAX_DQ_TIME; 210 h->qh_info.dqi_igrace = MAX_IQ_TIME; 211 h->qh_info.u.v2_mdqi.dqi_flags = 0; 212 h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks = QT_TREEOFF + 1; 213 h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk = 0; 214 h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = 0; 215 h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = 216 sizeof(struct v2r1_disk_dqblk); 217 h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; 218 v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); 219 if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, 220 sizeof(ddqinfo)) != 221 sizeof(ddqinfo)) 222 return -1; 223 224 return 0; 225 } 226 227 /* 228 * Write information (grace times to file) 229 */ 230 static int v2_write_info(struct quota_handle *h) 231 { 232 struct v2_disk_dqinfo ddqinfo; 233 234 v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); 235 if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, sizeof(ddqinfo)) != 236 sizeof(ddqinfo)) 237 return -1; 238 239 return 0; 240 } 241 242 /* 243 * Read dquot from disk 244 */ 245 static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) 246 { 247 return qtree_read_dquot(h, id); 248 } 249 250 /* 251 * Commit changes of dquot to disk - it might also mean deleting it when quota 252 * became fake one and user has no blocks. 253 * User can process use 'errno' to detect errstr. 254 */ 255 static int v2_commit_dquot(struct dquot *dquot) 256 { 257 struct util_dqblk *b = &dquot->dq_dqb; 258 259 if (!b->dqb_curspace && !b->dqb_curinodes && !b->dqb_bsoftlimit && 260 !b->dqb_isoftlimit && !b->dqb_bhardlimit && !b->dqb_ihardlimit) 261 qtree_delete_dquot(dquot); 262 else 263 qtree_write_dquot(dquot); 264 return 0; 265 } 266 267 static int v2_scan_dquots(struct quota_handle *h, 268 int (*process_dquot) (struct dquot *, void *), 269 void *data) 270 { 271 return qtree_scan_dquots(h, process_dquot, data); 272 } 273 274 /* Report information about quotafile. 275 * TODO: Not used right now, but we should be able to use this when we add 276 * support to debugfs to read quota files. 277 */ 278 static int v2_report(struct quota_handle *h, int verbose) 279 { 280 log_err("Not Implemented."); 281 return -1; 282 } 283