Home | History | Annotate | Download | only in fsck
      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 = &quotafile_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 = &quotafile_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