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