diff options
Diffstat (limited to 'fsck/quotaio.c')
-rw-r--r-- | fsck/quotaio.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/fsck/quotaio.c b/fsck/quotaio.c new file mode 100644 index 0000000..afadf56 --- /dev/null +++ b/fsck/quotaio.c @@ -0,0 +1,221 @@ +/** quotaio.c + * + * Generic IO operations on quotafiles + * Jan Kara <jack@suse.cz> - sponsored by SuSE CR + * Aditya Kali <adityakali@google.com> - Ported to e2fsprogs + * Hyojun Kim <hyojun@google.com> - Ported to f2fs-tools + */ + +#include "config.h" +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <assert.h> + +#include "common.h" +#include "quotaio.h" + +static const char * const extensions[MAXQUOTAS] = { + [USRQUOTA] = "user", + [GRPQUOTA] = "group", + [PRJQUOTA] = "project", +}; + +/* Header in all newer quotafiles */ +struct disk_dqheader { + __le32 dqh_magic; + __le32 dqh_version; +} __attribute__ ((packed)); + +/** + * Convert type of quota to written representation + */ +const char *quota_type2name(enum quota_type qtype) +{ + if (qtype >= MAXQUOTAS) + return "unknown"; + return extensions[qtype]; +} + +/* + * Set grace time if needed + */ +void update_grace_times(struct dquot *q) +{ + time_t now; + + time(&now); + if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) > + q->dq_dqb.dqb_bsoftlimit) { + if (!q->dq_dqb.dqb_btime) + q->dq_dqb.dqb_btime = + now + q->dq_h->qh_info.dqi_bgrace; + } else { + q->dq_dqb.dqb_btime = 0; + } + + if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes > + q->dq_dqb.dqb_isoftlimit) { + if (!q->dq_dqb.dqb_itime) + q->dq_dqb.dqb_itime = + now + q->dq_h->qh_info.dqi_igrace; + } else { + q->dq_dqb.dqb_itime = 0; + } +} + +/* Functions to read/write quota file. */ +static unsigned int quota_write_nomount(struct quota_file *qf, + long offset, + void *buf, unsigned int size) +{ + unsigned int written; + + written = f2fs_write(qf->sbi, qf->ino, buf, size, offset); + if (qf->filesize < offset + written) + qf->filesize = offset + written; + + return written; +} + +static unsigned int quota_read_nomount(struct quota_file *qf, long offset, + void *buf, unsigned int size) +{ + return f2fs_read(qf->sbi, qf->ino, buf, size, offset); +} + +/* + * Detect quota format and initialize quota IO + */ +errcode_t quota_file_open(struct f2fs_sb_info *sbi, struct quota_handle *h, + enum quota_type qtype, int flags) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + quota_ctx_t qctx = fsck->qctx; + f2fs_ino_t qf_ino; + errcode_t err = 0; + int allocated_handle = 0; + + if (qtype >= MAXQUOTAS) + return EINVAL; + + qf_ino = sb->qf_ino[qtype]; + + if (!h) { + if (qctx->quota_file[qtype]) { + h = qctx->quota_file[qtype]; + (void) quota_file_close(sbi, h, 0); + } + err = quota_get_mem(sizeof(struct quota_handle), &h); + if (err) { + log_err("Unable to allocate quota handle"); + return err; + } + allocated_handle = 1; + } + + h->qh_qf.sbi = sbi; + h->qh_qf.ino = qf_ino; + h->write = quota_write_nomount; + h->read = quota_read_nomount; + h->qh_file_flags = flags; + h->qh_io_flags = 0; + h->qh_type = qtype; + h->qh_fmt = QFMT_VFS_V1; + memset(&h->qh_info, 0, sizeof(h->qh_info)); + h->qh_ops = "afile_ops_2; + + if (h->qh_ops->check_file && + (h->qh_ops->check_file(h, qtype) == 0)) { + log_err("qh_ops->check_file failed"); + err = EIO; + goto errout; + } + + if (h->qh_ops->init_io && (h->qh_ops->init_io(h) < 0)) { + log_err("qh_ops->init_io failed"); + err = EIO; + goto errout; + } + if (allocated_handle) + qctx->quota_file[qtype] = h; +errout: + return err; +} + +/* + * Create new quotafile of specified format on given filesystem + */ +errcode_t quota_file_create(struct f2fs_sb_info *sbi, struct quota_handle *h, + enum quota_type qtype) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + f2fs_ino_t qf_inum = sb->qf_ino[qtype]; + errcode_t err = 0; + + h->qh_qf.sbi = sbi; + h->qh_qf.ino = qf_inum; + h->write = quota_write_nomount; + h->read = quota_read_nomount; + + log_debug("Creating quota ino=%u, type=%d", qf_inum, qtype); + h->qh_io_flags = 0; + h->qh_type = qtype; + h->qh_fmt = QFMT_VFS_V1; + memset(&h->qh_info, 0, sizeof(h->qh_info)); + h->qh_ops = "afile_ops_2; + + if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) { + log_err("qh_ops->new_io failed"); + err = EIO; + } + + return err; +} + +/* + * Close quotafile and release handle + */ +errcode_t quota_file_close(struct f2fs_sb_info *sbi, struct quota_handle *h, + int update_filesize) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + quota_ctx_t qctx = fsck->qctx; + + if (h->qh_io_flags & IOFL_INFODIRTY) { + if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0) + return EIO; + h->qh_io_flags &= ~IOFL_INFODIRTY; + } + if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0) + return EIO; + if (update_filesize) { + f2fs_filesize_update(sbi, h->qh_qf.ino, h->qh_qf.filesize); + } + if (qctx->quota_file[h->qh_type] == h) + quota_free_mem(&qctx->quota_file[h->qh_type]); + return 0; +} + +/* + * Create empty quota structure + */ +struct dquot *get_empty_dquot(void) +{ + struct dquot *dquot; + + if (quota_get_memzero(sizeof(struct dquot), &dquot)) { + log_err("Failed to allocate dquot"); + return NULL; + } + + dquot->dq_id = -1; + return dquot; +} |