L4Re/departure

libext2fs/lib/libsupport/quotaio_v2.c

617:2733e5770ee9
9 months ago Paul Boddie Made the run command wait for completion, introducing the spawn command to run programs in the background. Introduced conveniences for waiting for the last job to be initiated and for piping from the last job, also subscribing to signals from pipe-supplying jobs so that they may be transparently removed from the job list upon completion. Augmented the job listing with the "+" notation familiar from Unix. Prevented new jobs from being started when no job slots are available.
     1 /*     2  * Implementation of new quotafile format     3  *     4  * Jan Kara <jack@suse.cz> - sponsored by SuSE CR     5  */     6      7 #include "config.h"     8 #include <sys/types.h>     9 #include <errno.h>    10 #include <stdio.h>    11 #include <stdlib.h>    12 #include <string.h>    13 #include <unistd.h>    14     15 #include "common.h"    16 #include "quotaio_v2.h"    17 #include "dqblk_v2.h"    18 #include "quotaio.h"    19 #include "quotaio_tree.h"    20     21 static int v2_check_file(struct quota_handle *h, int type, int fmt);    22 static int v2_init_io(struct quota_handle *h);    23 static int v2_new_io(struct quota_handle *h);    24 static int v2_write_info(struct quota_handle *h);    25 static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id);    26 static int v2_commit_dquot(struct dquot *dquot);    27 static int v2_scan_dquots(struct quota_handle *h,    28 			  int (*process_dquot) (struct dquot *dquot,    29 						void *data),    30 			  void *data);    31 static int v2_report(struct quota_handle *h, int verbose);    32     33 struct quotafile_ops quotafile_ops_2 = {    34 	.check_file	= v2_check_file,    35 	.init_io 	= v2_init_io,    36 	.new_io 	= v2_new_io,    37 	.write_info	= v2_write_info,    38 	.read_dquot	= v2_read_dquot,    39 	.commit_dquot	= v2_commit_dquot,    40 	.scan_dquots	= v2_scan_dquots,    41 	.report		= v2_report,    42 };    43     44 /*    45  * Copy dquot from disk to memory    46  */    47 static void v2r1_disk2memdqblk(struct dquot *dquot, void *dp)    48 {    49 	struct util_dqblk *m = &dquot->dq_dqb;    50 	struct v2r1_disk_dqblk *d = dp, empty;    51     52 	dquot->dq_id = ext2fs_le32_to_cpu(d->dqb_id);    53 	m->dqb_ihardlimit = ext2fs_le64_to_cpu(d->dqb_ihardlimit);    54 	m->dqb_isoftlimit = ext2fs_le64_to_cpu(d->dqb_isoftlimit);    55 	m->dqb_bhardlimit = ext2fs_le64_to_cpu(d->dqb_bhardlimit);    56 	m->dqb_bsoftlimit = ext2fs_le64_to_cpu(d->dqb_bsoftlimit);    57 	m->dqb_curinodes = ext2fs_le64_to_cpu(d->dqb_curinodes);    58 	m->dqb_curspace = ext2fs_le64_to_cpu(d->dqb_curspace);    59 	m->dqb_itime = ext2fs_le64_to_cpu(d->dqb_itime);    60 	m->dqb_btime = ext2fs_le64_to_cpu(d->dqb_btime);    61     62 	memset(&empty, 0, sizeof(struct v2r1_disk_dqblk));    63 	empty.dqb_itime = ext2fs_cpu_to_le64(1);    64 	if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk)))    65 		m->dqb_itime = 0;    66 }    67     68 /*    69  * Copy dquot from memory to disk    70  */    71 static void v2r1_mem2diskdqblk(void *dp, struct dquot *dquot)    72 {    73 	struct util_dqblk *m = &dquot->dq_dqb;    74 	struct v2r1_disk_dqblk *d = dp;    75     76 	d->dqb_ihardlimit = ext2fs_cpu_to_le64(m->dqb_ihardlimit);    77 	d->dqb_isoftlimit = ext2fs_cpu_to_le64(m->dqb_isoftlimit);    78 	d->dqb_bhardlimit = ext2fs_cpu_to_le64(m->dqb_bhardlimit);    79 	d->dqb_bsoftlimit = ext2fs_cpu_to_le64(m->dqb_bsoftlimit);    80 	d->dqb_curinodes = ext2fs_cpu_to_le64(m->dqb_curinodes);    81 	d->dqb_curspace = ext2fs_cpu_to_le64(m->dqb_curspace);    82 	d->dqb_itime = ext2fs_cpu_to_le64(m->dqb_itime);    83 	d->dqb_btime = ext2fs_cpu_to_le64(m->dqb_btime);    84 	d->dqb_id = ext2fs_cpu_to_le32(dquot->dq_id);    85 	if (qtree_entry_unused(&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree, dp))    86 		d->dqb_itime = ext2fs_cpu_to_le64(1);    87 }    88     89 static int v2r1_is_id(void *dp, struct dquot *dquot)    90 {    91 	struct v2r1_disk_dqblk *d = dp;    92 	struct qtree_mem_dqinfo *info =    93 			&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree;    94     95 	if (qtree_entry_unused(info, dp))    96 		return 0;    97 	return ext2fs_le32_to_cpu(d->dqb_id) == dquot->dq_id;    98 }    99    100 static struct qtree_fmt_operations v2r1_fmt_ops = {   101 	.mem2disk_dqblk = v2r1_mem2diskdqblk,   102 	.disk2mem_dqblk = v2r1_disk2memdqblk,   103 	.is_id = v2r1_is_id,   104 };   105    106 /*   107  * Copy dqinfo from disk to memory   108  */   109 static inline void v2_disk2memdqinfo(struct util_dqinfo *m,   110 				     struct v2_disk_dqinfo *d)   111 {   112 	m->dqi_bgrace = ext2fs_le32_to_cpu(d->dqi_bgrace);   113 	m->dqi_igrace = ext2fs_le32_to_cpu(d->dqi_igrace);   114 	m->u.v2_mdqi.dqi_flags = ext2fs_le32_to_cpu(d->dqi_flags) & V2_DQF_MASK;   115 	m->u.v2_mdqi.dqi_qtree.dqi_blocks = ext2fs_le32_to_cpu(d->dqi_blocks);   116 	m->u.v2_mdqi.dqi_qtree.dqi_free_blk =   117 		ext2fs_le32_to_cpu(d->dqi_free_blk);   118 	m->u.v2_mdqi.dqi_qtree.dqi_free_entry =   119 				ext2fs_le32_to_cpu(d->dqi_free_entry);   120 }   121    122 /*   123  * Copy dqinfo from memory to disk   124  */   125 static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d,   126 				     struct util_dqinfo *m)   127 {   128 	d->dqi_bgrace = ext2fs_cpu_to_le32(m->dqi_bgrace);   129 	d->dqi_igrace = ext2fs_cpu_to_le32(m->dqi_igrace);   130 	d->dqi_flags = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_flags & V2_DQF_MASK);   131 	d->dqi_blocks = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_blocks);   132 	d->dqi_free_blk =   133 		ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_blk);   134 	d->dqi_free_entry =   135 		ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_entry);   136 }   137    138 static int v2_read_header(struct quota_handle *h, struct v2_disk_dqheader *dqh)   139 {   140 	if (h->e2fs_read(&h->qh_qf, 0, dqh, sizeof(struct v2_disk_dqheader)) !=   141 			sizeof(struct v2_disk_dqheader))   142 		return 0;   143    144 	return 1;   145 }   146    147 /*   148  * Check whether given quota file is in our format   149  */   150 static int v2_check_file(struct quota_handle *h, int type, int fmt)   151 {   152 	struct v2_disk_dqheader dqh;   153 	int file_magics[] = INITQMAGICS;   154 	int be_magic;   155    156 	if (fmt != QFMT_VFS_V1)   157 		return 0;   158    159 	if (!v2_read_header(h, &dqh))   160 		return 0;   161    162 	be_magic = ext2fs_be32_to_cpu((__force __be32)dqh.dqh_magic);   163 	if (be_magic == file_magics[type]) {   164 		log_err("Your quota file is stored in wrong endianity");   165 		return 0;   166 	}   167 	if (V2_VERSION != ext2fs_le32_to_cpu(dqh.dqh_version))   168 		return 0;   169 	return 1;   170 }   171    172 /*   173  * Open quotafile   174  */   175 static int v2_init_io(struct quota_handle *h)   176 {   177 	struct v2_disk_dqinfo ddqinfo;   178 	struct v2_mem_dqinfo *info;   179 	__u64 filesize;   180    181 	h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size =   182 		sizeof(struct v2r1_disk_dqblk);   183 	h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops;   184    185 	/* Read information about quotafile */   186 	if (h->e2fs_read(&h->qh_qf, V2_DQINFOOFF, &ddqinfo,   187 			 sizeof(ddqinfo)) != sizeof(ddqinfo))   188 		return -1;   189 	v2_disk2memdqinfo(&h->qh_info, &ddqinfo);   190    191 	/* Check to make sure quota file info is sane */   192 	info = &h->qh_info.u.v2_mdqi;   193 	if (ext2fs_file_get_lsize(h->qh_qf.e2_file, &filesize))   194 		return -1;   195 	if ((filesize > (1U << 31)) ||   196 	    (info->dqi_qtree.dqi_blocks >   197 	     (filesize + QT_BLKSIZE - 1) >> QT_BLKSIZE_BITS)) {   198 		log_err("Quota inode %u corrupted: file size %llu; "   199 			"dqi_blocks %u", h->qh_qf.ino,   200 			(unsigned long long) filesize,   201 			info->dqi_qtree.dqi_blocks);   202 		return -1;   203 	}   204 	if (info->dqi_qtree.dqi_free_blk >= info->dqi_qtree.dqi_blocks) {   205 		log_err("Quota inode %u corrupted: free_blk %u; dqi_blocks %u",   206 			h->qh_qf.ino, info->dqi_qtree.dqi_free_blk,   207 			info->dqi_qtree.dqi_blocks);   208 		return -1;   209 	}   210 	if (info->dqi_qtree.dqi_free_entry >= info->dqi_qtree.dqi_blocks) {   211 		log_err("Quota inode %u corrupted: free_entry %u; "   212 			"dqi_blocks %u", h->qh_qf.ino,   213 			info->dqi_qtree.dqi_free_entry,   214 			info->dqi_qtree.dqi_blocks);   215 		return -1;   216 	}   217 	return 0;   218 }   219    220 /*   221  * Initialize new quotafile   222  */   223 static int v2_new_io(struct quota_handle *h)   224 {   225 	int file_magics[] = INITQMAGICS;   226 	struct v2_disk_dqheader ddqheader;   227 	struct v2_disk_dqinfo ddqinfo;   228    229 	if (h->qh_fmt != QFMT_VFS_V1)   230 		return -1;   231    232 	/* Write basic quota header */   233 	ddqheader.dqh_magic = ext2fs_cpu_to_le32(file_magics[h->qh_type]);   234 	ddqheader.dqh_version = ext2fs_cpu_to_le32(V2_VERSION);   235 	if (h->e2fs_write(&h->qh_qf, 0, &ddqheader, sizeof(ddqheader)) !=   236 			sizeof(ddqheader))   237 		return -1;   238    239 	/* Write information about quotafile */   240 	h->qh_info.dqi_bgrace = MAX_DQ_TIME;   241 	h->qh_info.dqi_igrace = MAX_IQ_TIME;   242 	h->qh_info.u.v2_mdqi.dqi_flags = 0;   243 	h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks = QT_TREEOFF + 1;   244 	h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk = 0;   245 	h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = 0;   246 	h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size =   247 				sizeof(struct v2r1_disk_dqblk);   248 	h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops;   249 	v2_mem2diskdqinfo(&ddqinfo, &h->qh_info);   250 	if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo,   251 			  sizeof(ddqinfo)) !=   252 	    sizeof(ddqinfo))   253 		return -1;   254    255 	return 0;   256 }   257    258 /*   259  * Write information (grace times to file)   260  */   261 static int v2_write_info(struct quota_handle *h)   262 {   263 	struct v2_disk_dqinfo ddqinfo;   264    265 	v2_mem2diskdqinfo(&ddqinfo, &h->qh_info);   266 	if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, sizeof(ddqinfo)) !=   267 			sizeof(ddqinfo))   268 		return -1;   269    270 	return 0;   271 }   272    273 /*   274  * Read dquot from disk   275  */   276 static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id)   277 {   278 	return qtree_read_dquot(h, id);   279 }   280    281 /*   282  * Commit changes of dquot to disk - it might also mean deleting it when quota   283  * became fake one and user has no blocks.   284  * User can process use 'errno' to detect errstr.   285  */   286 static int v2_commit_dquot(struct dquot *dquot)   287 {   288 	struct util_dqblk *b = &dquot->dq_dqb;   289    290 	if (!b->dqb_curspace && !b->dqb_curinodes && !b->dqb_bsoftlimit &&   291 	    !b->dqb_isoftlimit && !b->dqb_bhardlimit && !b->dqb_ihardlimit)   292 		qtree_delete_dquot(dquot);   293 	else   294 		qtree_write_dquot(dquot);   295 	return 0;   296 }   297    298 static int v2_scan_dquots(struct quota_handle *h,   299 			  int (*process_dquot) (struct dquot *, void *),   300 			  void *data)   301 {   302 	return qtree_scan_dquots(h, process_dquot, data);   303 }   304    305 /* Report information about quotafile.   306  * TODO: Not used right now, but we should be able to use this when we add   307  * support to debugfs to read quota files.   308  */   309 static int v2_report(struct quota_handle *h EXT2FS_ATTR((unused)),   310 		     int verbose EXT2FS_ATTR((unused)))   311 {   312 	log_err("Not Implemented.");   313 	return -1;   314 }