15e5c12b0Sopenharmony_ci/** quotaio.c 25e5c12b0Sopenharmony_ci * 35e5c12b0Sopenharmony_ci * Generic IO operations on quotafiles 45e5c12b0Sopenharmony_ci * Jan Kara <jack@suse.cz> - sponsored by SuSE CR 55e5c12b0Sopenharmony_ci * Aditya Kali <adityakali@google.com> - Ported to e2fsprogs 65e5c12b0Sopenharmony_ci * Hyojun Kim <hyojun@google.com> - Ported to f2fs-tools 75e5c12b0Sopenharmony_ci */ 85e5c12b0Sopenharmony_ci 95e5c12b0Sopenharmony_ci#include <stdio.h> 105e5c12b0Sopenharmony_ci#include <errno.h> 115e5c12b0Sopenharmony_ci#include <string.h> 125e5c12b0Sopenharmony_ci#include <unistd.h> 135e5c12b0Sopenharmony_ci#include <stdlib.h> 145e5c12b0Sopenharmony_ci#include <time.h> 155e5c12b0Sopenharmony_ci#include <sys/types.h> 165e5c12b0Sopenharmony_ci#include <sys/stat.h> 175e5c12b0Sopenharmony_ci#include <sys/file.h> 185e5c12b0Sopenharmony_ci#include <assert.h> 195e5c12b0Sopenharmony_ci 205e5c12b0Sopenharmony_ci#include "common.h" 215e5c12b0Sopenharmony_ci#include "quotaio.h" 225e5c12b0Sopenharmony_ci 235e5c12b0Sopenharmony_cistatic const char * const extensions[MAXQUOTAS] = { 245e5c12b0Sopenharmony_ci [USRQUOTA] = "user", 255e5c12b0Sopenharmony_ci [GRPQUOTA] = "group", 265e5c12b0Sopenharmony_ci [PRJQUOTA] = "project", 275e5c12b0Sopenharmony_ci}; 285e5c12b0Sopenharmony_ci 295e5c12b0Sopenharmony_ci/* Header in all newer quotafiles */ 305e5c12b0Sopenharmony_cistruct disk_dqheader { 315e5c12b0Sopenharmony_ci __le32 dqh_magic; 325e5c12b0Sopenharmony_ci __le32 dqh_version; 335e5c12b0Sopenharmony_ci}; 345e5c12b0Sopenharmony_ci 355e5c12b0Sopenharmony_cistatic_assert(sizeof(struct disk_dqheader) == 8, ""); 365e5c12b0Sopenharmony_ci 375e5c12b0Sopenharmony_ciint cur_qtype = -1; 385e5c12b0Sopenharmony_ciu32 qf_last_blkofs[MAXQUOTAS] = {0, 0, 0}; 395e5c12b0Sopenharmony_cienum qf_szchk_type_t qf_szchk_type[MAXQUOTAS] = 405e5c12b0Sopenharmony_ci{ 415e5c12b0Sopenharmony_ci QF_SZCHK_NONE, QF_SZCHK_NONE, QF_SZCHK_NONE 425e5c12b0Sopenharmony_ci}; 435e5c12b0Sopenharmony_ciu64 qf_maxsize[MAXQUOTAS]; 445e5c12b0Sopenharmony_ci 455e5c12b0Sopenharmony_ci/** 465e5c12b0Sopenharmony_ci * Convert type of quota to written representation 475e5c12b0Sopenharmony_ci */ 485e5c12b0Sopenharmony_ciconst char *quota_type2name(enum quota_type qtype) 495e5c12b0Sopenharmony_ci{ 505e5c12b0Sopenharmony_ci if (qtype >= MAXQUOTAS) 515e5c12b0Sopenharmony_ci return "unknown"; 525e5c12b0Sopenharmony_ci return extensions[qtype]; 535e5c12b0Sopenharmony_ci} 545e5c12b0Sopenharmony_ci 555e5c12b0Sopenharmony_ci/* 565e5c12b0Sopenharmony_ci * Set grace time if needed 575e5c12b0Sopenharmony_ci */ 585e5c12b0Sopenharmony_civoid update_grace_times(struct dquot *q) 595e5c12b0Sopenharmony_ci{ 605e5c12b0Sopenharmony_ci time_t now; 615e5c12b0Sopenharmony_ci 625e5c12b0Sopenharmony_ci time(&now); 635e5c12b0Sopenharmony_ci if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) > 645e5c12b0Sopenharmony_ci q->dq_dqb.dqb_bsoftlimit) { 655e5c12b0Sopenharmony_ci if (!q->dq_dqb.dqb_btime) 665e5c12b0Sopenharmony_ci q->dq_dqb.dqb_btime = 675e5c12b0Sopenharmony_ci now + q->dq_h->qh_info.dqi_bgrace; 685e5c12b0Sopenharmony_ci } else { 695e5c12b0Sopenharmony_ci q->dq_dqb.dqb_btime = 0; 705e5c12b0Sopenharmony_ci } 715e5c12b0Sopenharmony_ci 725e5c12b0Sopenharmony_ci if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes > 735e5c12b0Sopenharmony_ci q->dq_dqb.dqb_isoftlimit) { 745e5c12b0Sopenharmony_ci if (!q->dq_dqb.dqb_itime) 755e5c12b0Sopenharmony_ci q->dq_dqb.dqb_itime = 765e5c12b0Sopenharmony_ci now + q->dq_h->qh_info.dqi_igrace; 775e5c12b0Sopenharmony_ci } else { 785e5c12b0Sopenharmony_ci q->dq_dqb.dqb_itime = 0; 795e5c12b0Sopenharmony_ci } 805e5c12b0Sopenharmony_ci} 815e5c12b0Sopenharmony_ci 825e5c12b0Sopenharmony_ci/* Functions to read/write quota file. */ 835e5c12b0Sopenharmony_cistatic unsigned int quota_write_nomount(struct quota_file *qf, 845e5c12b0Sopenharmony_ci long offset, 855e5c12b0Sopenharmony_ci void *buf, unsigned int size) 865e5c12b0Sopenharmony_ci{ 875e5c12b0Sopenharmony_ci unsigned int written; 885e5c12b0Sopenharmony_ci 895e5c12b0Sopenharmony_ci written = f2fs_write(qf->sbi, qf->ino, buf, size, offset); 905e5c12b0Sopenharmony_ci if (qf->filesize < offset + written) 915e5c12b0Sopenharmony_ci qf->filesize = offset + written; 925e5c12b0Sopenharmony_ci if (written != size) 935e5c12b0Sopenharmony_ci return -EIO; 945e5c12b0Sopenharmony_ci return written; 955e5c12b0Sopenharmony_ci} 965e5c12b0Sopenharmony_ci 975e5c12b0Sopenharmony_cistatic unsigned int quota_read_nomount(struct quota_file *qf, long offset, 985e5c12b0Sopenharmony_ci void *buf, unsigned int size) 995e5c12b0Sopenharmony_ci{ 1005e5c12b0Sopenharmony_ci return f2fs_read(qf->sbi, qf->ino, buf, size, offset); 1015e5c12b0Sopenharmony_ci} 1025e5c12b0Sopenharmony_ci 1035e5c12b0Sopenharmony_ci/* 1045e5c12b0Sopenharmony_ci * Detect quota format and initialize quota IO 1055e5c12b0Sopenharmony_ci */ 1065e5c12b0Sopenharmony_cierrcode_t quota_file_open(struct f2fs_sb_info *sbi, struct quota_handle *h, 1075e5c12b0Sopenharmony_ci enum quota_type qtype, int flags) 1085e5c12b0Sopenharmony_ci{ 1095e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 1105e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 1115e5c12b0Sopenharmony_ci quota_ctx_t qctx = fsck->qctx; 1125e5c12b0Sopenharmony_ci f2fs_ino_t qf_ino; 1135e5c12b0Sopenharmony_ci errcode_t err = 0; 1145e5c12b0Sopenharmony_ci int allocated_handle = 0; 1155e5c12b0Sopenharmony_ci 1165e5c12b0Sopenharmony_ci if (qtype >= MAXQUOTAS) 1175e5c12b0Sopenharmony_ci return EINVAL; 1185e5c12b0Sopenharmony_ci 1195e5c12b0Sopenharmony_ci qf_ino = sb->qf_ino[qtype]; 1205e5c12b0Sopenharmony_ci 1215e5c12b0Sopenharmony_ci if (!h) { 1225e5c12b0Sopenharmony_ci if (qctx->quota_file[qtype]) { 1235e5c12b0Sopenharmony_ci h = qctx->quota_file[qtype]; 1245e5c12b0Sopenharmony_ci (void) quota_file_close(sbi, h, 0); 1255e5c12b0Sopenharmony_ci } 1265e5c12b0Sopenharmony_ci err = quota_get_mem(sizeof(struct quota_handle), &h); 1275e5c12b0Sopenharmony_ci if (err) { 1285e5c12b0Sopenharmony_ci log_err("Unable to allocate quota handle"); 1295e5c12b0Sopenharmony_ci return err; 1305e5c12b0Sopenharmony_ci } 1315e5c12b0Sopenharmony_ci allocated_handle = 1; 1325e5c12b0Sopenharmony_ci } 1335e5c12b0Sopenharmony_ci 1345e5c12b0Sopenharmony_ci h->qh_qf.sbi = sbi; 1355e5c12b0Sopenharmony_ci h->qh_qf.ino = qf_ino; 1365e5c12b0Sopenharmony_ci h->write = quota_write_nomount; 1375e5c12b0Sopenharmony_ci h->read = quota_read_nomount; 1385e5c12b0Sopenharmony_ci h->qh_file_flags = flags; 1395e5c12b0Sopenharmony_ci h->qh_io_flags = 0; 1405e5c12b0Sopenharmony_ci h->qh_type = qtype; 1415e5c12b0Sopenharmony_ci h->qh_fmt = QFMT_VFS_V1; 1425e5c12b0Sopenharmony_ci memset(&h->qh_info, 0, sizeof(h->qh_info)); 1435e5c12b0Sopenharmony_ci h->qh_ops = "afile_ops_2; 1445e5c12b0Sopenharmony_ci 1455e5c12b0Sopenharmony_ci if (h->qh_ops->check_file && 1465e5c12b0Sopenharmony_ci (h->qh_ops->check_file(h, qtype) == 0)) { 1475e5c12b0Sopenharmony_ci log_err("qh_ops->check_file failed"); 1485e5c12b0Sopenharmony_ci err = EIO; 1495e5c12b0Sopenharmony_ci goto errout; 1505e5c12b0Sopenharmony_ci } 1515e5c12b0Sopenharmony_ci 1525e5c12b0Sopenharmony_ci if (h->qh_ops->init_io && (h->qh_ops->init_io(h, qtype) < 0)) { 1535e5c12b0Sopenharmony_ci log_err("qh_ops->init_io failed"); 1545e5c12b0Sopenharmony_ci err = EIO; 1555e5c12b0Sopenharmony_ci goto errout; 1565e5c12b0Sopenharmony_ci } 1575e5c12b0Sopenharmony_ci if (allocated_handle) 1585e5c12b0Sopenharmony_ci qctx->quota_file[qtype] = h; 1595e5c12b0Sopenharmony_cierrout: 1605e5c12b0Sopenharmony_ci return err; 1615e5c12b0Sopenharmony_ci} 1625e5c12b0Sopenharmony_ci 1635e5c12b0Sopenharmony_ci/* 1645e5c12b0Sopenharmony_ci * Create new quotafile of specified format on given filesystem 1655e5c12b0Sopenharmony_ci */ 1665e5c12b0Sopenharmony_cierrcode_t quota_file_create(struct f2fs_sb_info *sbi, struct quota_handle *h, 1675e5c12b0Sopenharmony_ci enum quota_type qtype) 1685e5c12b0Sopenharmony_ci{ 1695e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 1705e5c12b0Sopenharmony_ci f2fs_ino_t qf_inum = sb->qf_ino[qtype]; 1715e5c12b0Sopenharmony_ci errcode_t err = 0; 1725e5c12b0Sopenharmony_ci 1735e5c12b0Sopenharmony_ci memset(&h->qh_qf, 0, sizeof(h->qh_qf)); 1745e5c12b0Sopenharmony_ci h->qh_qf.sbi = sbi; 1755e5c12b0Sopenharmony_ci h->qh_qf.ino = qf_inum; 1765e5c12b0Sopenharmony_ci h->write = quota_write_nomount; 1775e5c12b0Sopenharmony_ci h->read = quota_read_nomount; 1785e5c12b0Sopenharmony_ci 1795e5c12b0Sopenharmony_ci log_debug("Creating quota ino=%u, type=%d", qf_inum, qtype); 1805e5c12b0Sopenharmony_ci h->qh_io_flags = 0; 1815e5c12b0Sopenharmony_ci h->qh_type = qtype; 1825e5c12b0Sopenharmony_ci h->qh_fmt = QFMT_VFS_V1; 1835e5c12b0Sopenharmony_ci memset(&h->qh_info, 0, sizeof(h->qh_info)); 1845e5c12b0Sopenharmony_ci h->qh_ops = "afile_ops_2; 1855e5c12b0Sopenharmony_ci 1865e5c12b0Sopenharmony_ci if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) { 1875e5c12b0Sopenharmony_ci log_err("qh_ops->new_io failed"); 1885e5c12b0Sopenharmony_ci err = EIO; 1895e5c12b0Sopenharmony_ci } 1905e5c12b0Sopenharmony_ci 1915e5c12b0Sopenharmony_ci return err; 1925e5c12b0Sopenharmony_ci} 1935e5c12b0Sopenharmony_ci 1945e5c12b0Sopenharmony_ci/* 1955e5c12b0Sopenharmony_ci * Close quotafile and release handle 1965e5c12b0Sopenharmony_ci */ 1975e5c12b0Sopenharmony_cierrcode_t quota_file_close(struct f2fs_sb_info *sbi, struct quota_handle *h, 1985e5c12b0Sopenharmony_ci int update_filesize) 1995e5c12b0Sopenharmony_ci{ 2005e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 2015e5c12b0Sopenharmony_ci quota_ctx_t qctx = fsck->qctx; 2025e5c12b0Sopenharmony_ci 2035e5c12b0Sopenharmony_ci if (h->qh_io_flags & IOFL_INFODIRTY) { 2045e5c12b0Sopenharmony_ci if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0) 2055e5c12b0Sopenharmony_ci return EIO; 2065e5c12b0Sopenharmony_ci h->qh_io_flags &= ~IOFL_INFODIRTY; 2075e5c12b0Sopenharmony_ci } 2085e5c12b0Sopenharmony_ci if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0) 2095e5c12b0Sopenharmony_ci return EIO; 2105e5c12b0Sopenharmony_ci if (update_filesize) { 2115e5c12b0Sopenharmony_ci f2fs_filesize_update(sbi, h->qh_qf.ino, h->qh_qf.filesize); 2125e5c12b0Sopenharmony_ci } 2135e5c12b0Sopenharmony_ci if (qctx->quota_file[h->qh_type] == h) 2145e5c12b0Sopenharmony_ci quota_free_mem(&qctx->quota_file[h->qh_type]); 2155e5c12b0Sopenharmony_ci return 0; 2165e5c12b0Sopenharmony_ci} 2175e5c12b0Sopenharmony_ci 2185e5c12b0Sopenharmony_ci/* 2195e5c12b0Sopenharmony_ci * Create empty quota structure 2205e5c12b0Sopenharmony_ci */ 2215e5c12b0Sopenharmony_cistruct dquot *get_empty_dquot(void) 2225e5c12b0Sopenharmony_ci{ 2235e5c12b0Sopenharmony_ci struct dquot *dquot; 2245e5c12b0Sopenharmony_ci 2255e5c12b0Sopenharmony_ci if (quota_get_memzero(sizeof(struct dquot), &dquot)) { 2265e5c12b0Sopenharmony_ci log_err("Failed to allocate dquot"); 2275e5c12b0Sopenharmony_ci return NULL; 2285e5c12b0Sopenharmony_ci } 2295e5c12b0Sopenharmony_ci 2305e5c12b0Sopenharmony_ci dquot->dq_id = -1; 2315e5c12b0Sopenharmony_ci return dquot; 2325e5c12b0Sopenharmony_ci} 233