L4Re/departure

Annotated libext2fs/lib/libsupport/quotaio_v2.c

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