1 /** quotaio.c 2 * 3 * Generic IO operations on quotafiles 4 * Jan Kara <jack@suse.cz> - sponsored by SuSE CR 5 * Aditya Kali <adityakali@google.com> - Ported to e2fsprogs 6 * Hyojun Kim <hyojun@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 if (written != size) 84 return -EIO; 85 return written; 86 } 87 88 static unsigned int quota_read_nomount(struct quota_file *qf, long offset, 89 void *buf, unsigned int size) 90 { 91 return f2fs_read(qf->sbi, qf->ino, buf, size, offset); 92 } 93 94 /* 95 * Detect quota format and initialize quota IO 96 */ 97 errcode_t quota_file_open(struct f2fs_sb_info *sbi, struct quota_handle *h, 98 enum quota_type qtype, int flags) 99 { 100 struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 101 struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 102 quota_ctx_t qctx = fsck->qctx; 103 f2fs_ino_t qf_ino; 104 errcode_t err = 0; 105 int allocated_handle = 0; 106 107 if (qtype >= MAXQUOTAS) 108 return EINVAL; 109 110 qf_ino = sb->qf_ino[qtype]; 111 112 if (!h) { 113 if (qctx->quota_file[qtype]) { 114 h = qctx->quota_file[qtype]; 115 (void) quota_file_close(sbi, h, 0); 116 } 117 err = quota_get_mem(sizeof(struct quota_handle), &h); 118 if (err) { 119 log_err("Unable to allocate quota handle"); 120 return err; 121 } 122 allocated_handle = 1; 123 } 124 125 h->qh_qf.sbi = sbi; 126 h->qh_qf.ino = qf_ino; 127 h->write = quota_write_nomount; 128 h->read = quota_read_nomount; 129 h->qh_file_flags = flags; 130 h->qh_io_flags = 0; 131 h->qh_type = qtype; 132 h->qh_fmt = QFMT_VFS_V1; 133 memset(&h->qh_info, 0, sizeof(h->qh_info)); 134 h->qh_ops = "afile_ops_2; 135 136 if (h->qh_ops->check_file && 137 (h->qh_ops->check_file(h, qtype) == 0)) { 138 log_err("qh_ops->check_file failed"); 139 err = EIO; 140 goto errout; 141 } 142 143 if (h->qh_ops->init_io && (h->qh_ops->init_io(h) < 0)) { 144 log_err("qh_ops->init_io failed"); 145 err = EIO; 146 goto errout; 147 } 148 if (allocated_handle) 149 qctx->quota_file[qtype] = h; 150 errout: 151 return err; 152 } 153 154 /* 155 * Create new quotafile of specified format on given filesystem 156 */ 157 errcode_t quota_file_create(struct f2fs_sb_info *sbi, struct quota_handle *h, 158 enum quota_type qtype) 159 { 160 struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 161 f2fs_ino_t qf_inum = sb->qf_ino[qtype]; 162 errcode_t err = 0; 163 164 memset(&h->qh_qf, 0, sizeof(h->qh_qf)); 165 h->qh_qf.sbi = sbi; 166 h->qh_qf.ino = qf_inum; 167 h->write = quota_write_nomount; 168 h->read = quota_read_nomount; 169 170 log_debug("Creating quota ino=%u, type=%d", qf_inum, qtype); 171 h->qh_io_flags = 0; 172 h->qh_type = qtype; 173 h->qh_fmt = QFMT_VFS_V1; 174 memset(&h->qh_info, 0, sizeof(h->qh_info)); 175 h->qh_ops = "afile_ops_2; 176 177 if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) { 178 log_err("qh_ops->new_io failed"); 179 err = EIO; 180 } 181 182 return err; 183 } 184 185 /* 186 * Close quotafile and release handle 187 */ 188 errcode_t quota_file_close(struct f2fs_sb_info *sbi, struct quota_handle *h, 189 int update_filesize) 190 { 191 struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 192 quota_ctx_t qctx = fsck->qctx; 193 194 if (h->qh_io_flags & IOFL_INFODIRTY) { 195 if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0) 196 return EIO; 197 h->qh_io_flags &= ~IOFL_INFODIRTY; 198 } 199 if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0) 200 return EIO; 201 if (update_filesize) { 202 f2fs_filesize_update(sbi, h->qh_qf.ino, h->qh_qf.filesize); 203 } 204 if (qctx->quota_file[h->qh_type] == h) 205 quota_free_mem(&qctx->quota_file[h->qh_type]); 206 return 0; 207 } 208 209 /* 210 * Create empty quota structure 211 */ 212 struct dquot *get_empty_dquot(void) 213 { 214 struct dquot *dquot; 215 216 if (quota_get_memzero(sizeof(struct dquot), &dquot)) { 217 log_err("Failed to allocate dquot"); 218 return NULL; 219 } 220 221 dquot->dq_id = -1; 222 return dquot; 223 } 224