cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

quota_v2.c (12923B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *	vfsv0 quota IO operations on file
      4 */
      5
      6#include <linux/errno.h>
      7#include <linux/fs.h>
      8#include <linux/mount.h>
      9#include <linux/dqblk_v2.h>
     10#include <linux/kernel.h>
     11#include <linux/init.h>
     12#include <linux/module.h>
     13#include <linux/slab.h>
     14#include <linux/quotaops.h>
     15
     16#include <asm/byteorder.h>
     17
     18#include "quota_tree.h"
     19#include "quotaio_v2.h"
     20
     21MODULE_AUTHOR("Jan Kara");
     22MODULE_DESCRIPTION("Quota format v2 support");
     23MODULE_LICENSE("GPL");
     24
     25static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot);
     26static void v2r0_disk2memdqb(struct dquot *dquot, void *dp);
     27static int v2r0_is_id(void *dp, struct dquot *dquot);
     28static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
     29static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
     30static int v2r1_is_id(void *dp, struct dquot *dquot);
     31
     32static const struct qtree_fmt_operations v2r0_qtree_ops = {
     33	.mem2disk_dqblk = v2r0_mem2diskdqb,
     34	.disk2mem_dqblk = v2r0_disk2memdqb,
     35	.is_id = v2r0_is_id,
     36};
     37
     38static const struct qtree_fmt_operations v2r1_qtree_ops = {
     39	.mem2disk_dqblk = v2r1_mem2diskdqb,
     40	.disk2mem_dqblk = v2r1_disk2memdqb,
     41	.is_id = v2r1_is_id,
     42};
     43
     44#define QUOTABLOCK_BITS 10
     45#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
     46
     47static inline qsize_t v2_stoqb(qsize_t space)
     48{
     49	return (space + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS;
     50}
     51
     52static inline qsize_t v2_qbtos(qsize_t blocks)
     53{
     54	return blocks << QUOTABLOCK_BITS;
     55}
     56
     57static int v2_read_header(struct super_block *sb, int type,
     58			  struct v2_disk_dqheader *dqhead)
     59{
     60	ssize_t size;
     61
     62	size = sb->s_op->quota_read(sb, type, (char *)dqhead,
     63				    sizeof(struct v2_disk_dqheader), 0);
     64	if (size != sizeof(struct v2_disk_dqheader)) {
     65		quota_error(sb, "Failed header read: expected=%zd got=%zd",
     66			    sizeof(struct v2_disk_dqheader), size);
     67		if (size < 0)
     68			return size;
     69		return -EIO;
     70	}
     71	return 0;
     72}
     73
     74/* Check whether given file is really vfsv0 quotafile */
     75static int v2_check_quota_file(struct super_block *sb, int type)
     76{
     77	struct v2_disk_dqheader dqhead;
     78	static const uint quota_magics[] = V2_INITQMAGICS;
     79	static const uint quota_versions[] = V2_INITQVERSIONS;
     80
     81	if (v2_read_header(sb, type, &dqhead))
     82		return 0;
     83	if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
     84	    le32_to_cpu(dqhead.dqh_version) > quota_versions[type])
     85		return 0;
     86	return 1;
     87}
     88
     89/* Read information header from quota file */
     90static int v2_read_file_info(struct super_block *sb, int type)
     91{
     92	struct v2_disk_dqinfo dinfo;
     93	struct v2_disk_dqheader dqhead;
     94	struct quota_info *dqopt = sb_dqopt(sb);
     95	struct mem_dqinfo *info = &dqopt->info[type];
     96	struct qtree_mem_dqinfo *qinfo;
     97	ssize_t size;
     98	unsigned int version;
     99	int ret;
    100
    101	down_read(&dqopt->dqio_sem);
    102	ret = v2_read_header(sb, type, &dqhead);
    103	if (ret < 0)
    104		goto out;
    105	version = le32_to_cpu(dqhead.dqh_version);
    106	if ((info->dqi_fmt_id == QFMT_VFS_V0 && version != 0) ||
    107	    (info->dqi_fmt_id == QFMT_VFS_V1 && version != 1)) {
    108		ret = -EINVAL;
    109		goto out;
    110	}
    111
    112	size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
    113	       sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
    114	if (size != sizeof(struct v2_disk_dqinfo)) {
    115		quota_error(sb, "Can't read info structure");
    116		if (size < 0)
    117			ret = size;
    118		else
    119			ret = -EIO;
    120		goto out;
    121	}
    122	info->dqi_priv = kmalloc(sizeof(struct qtree_mem_dqinfo), GFP_NOFS);
    123	if (!info->dqi_priv) {
    124		ret = -ENOMEM;
    125		goto out;
    126	}
    127	qinfo = info->dqi_priv;
    128	if (version == 0) {
    129		/* limits are stored as unsigned 32-bit data */
    130		info->dqi_max_spc_limit = 0xffffffffLL << QUOTABLOCK_BITS;
    131		info->dqi_max_ino_limit = 0xffffffff;
    132	} else {
    133		/*
    134		 * Used space is stored as unsigned 64-bit value in bytes but
    135		 * quota core supports only signed 64-bit values so use that
    136		 * as a limit
    137		 */
    138		info->dqi_max_spc_limit = 0x7fffffffffffffffLL; /* 2^63-1 */
    139		info->dqi_max_ino_limit = 0x7fffffffffffffffLL;
    140	}
    141	info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
    142	info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
    143	/* No flags currently supported */
    144	info->dqi_flags = 0;
    145	qinfo->dqi_sb = sb;
    146	qinfo->dqi_type = type;
    147	qinfo->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
    148	qinfo->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
    149	qinfo->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
    150	qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
    151	qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
    152	qinfo->dqi_qtree_depth = qtree_depth(qinfo);
    153	if (version == 0) {
    154		qinfo->dqi_entry_size = sizeof(struct v2r0_disk_dqblk);
    155		qinfo->dqi_ops = &v2r0_qtree_ops;
    156	} else {
    157		qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk);
    158		qinfo->dqi_ops = &v2r1_qtree_ops;
    159	}
    160	ret = -EUCLEAN;
    161	/* Some sanity checks of the read headers... */
    162	if ((loff_t)qinfo->dqi_blocks << qinfo->dqi_blocksize_bits >
    163	    i_size_read(sb_dqopt(sb)->files[type])) {
    164		quota_error(sb, "Number of blocks too big for quota file size (%llu > %llu).",
    165		    (loff_t)qinfo->dqi_blocks << qinfo->dqi_blocksize_bits,
    166		    i_size_read(sb_dqopt(sb)->files[type]));
    167		goto out_free;
    168	}
    169	if (qinfo->dqi_free_blk >= qinfo->dqi_blocks) {
    170		quota_error(sb, "Free block number too big (%u >= %u).",
    171			    qinfo->dqi_free_blk, qinfo->dqi_blocks);
    172		goto out_free;
    173	}
    174	if (qinfo->dqi_free_entry >= qinfo->dqi_blocks) {
    175		quota_error(sb, "Block with free entry too big (%u >= %u).",
    176			    qinfo->dqi_free_entry, qinfo->dqi_blocks);
    177		goto out_free;
    178	}
    179	ret = 0;
    180out_free:
    181	if (ret) {
    182		kfree(info->dqi_priv);
    183		info->dqi_priv = NULL;
    184	}
    185out:
    186	up_read(&dqopt->dqio_sem);
    187	return ret;
    188}
    189
    190/* Write information header to quota file */
    191static int v2_write_file_info(struct super_block *sb, int type)
    192{
    193	struct v2_disk_dqinfo dinfo;
    194	struct quota_info *dqopt = sb_dqopt(sb);
    195	struct mem_dqinfo *info = &dqopt->info[type];
    196	struct qtree_mem_dqinfo *qinfo = info->dqi_priv;
    197	ssize_t size;
    198
    199	down_write(&dqopt->dqio_sem);
    200	spin_lock(&dq_data_lock);
    201	info->dqi_flags &= ~DQF_INFO_DIRTY;
    202	dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
    203	dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
    204	/* No flags currently supported */
    205	dinfo.dqi_flags = cpu_to_le32(0);
    206	spin_unlock(&dq_data_lock);
    207	dinfo.dqi_blocks = cpu_to_le32(qinfo->dqi_blocks);
    208	dinfo.dqi_free_blk = cpu_to_le32(qinfo->dqi_free_blk);
    209	dinfo.dqi_free_entry = cpu_to_le32(qinfo->dqi_free_entry);
    210	size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
    211	       sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
    212	up_write(&dqopt->dqio_sem);
    213	if (size != sizeof(struct v2_disk_dqinfo)) {
    214		quota_error(sb, "Can't write info structure");
    215		return -1;
    216	}
    217	return 0;
    218}
    219
    220static void v2r0_disk2memdqb(struct dquot *dquot, void *dp)
    221{
    222	struct v2r0_disk_dqblk *d = dp, empty;
    223	struct mem_dqblk *m = &dquot->dq_dqb;
    224
    225	m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
    226	m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
    227	m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
    228	m->dqb_itime = le64_to_cpu(d->dqb_itime);
    229	m->dqb_bhardlimit = v2_qbtos(le32_to_cpu(d->dqb_bhardlimit));
    230	m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit));
    231	m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
    232	m->dqb_btime = le64_to_cpu(d->dqb_btime);
    233	/* We need to escape back all-zero structure */
    234	memset(&empty, 0, sizeof(struct v2r0_disk_dqblk));
    235	empty.dqb_itime = cpu_to_le64(1);
    236	if (!memcmp(&empty, dp, sizeof(struct v2r0_disk_dqblk)))
    237		m->dqb_itime = 0;
    238}
    239
    240static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
    241{
    242	struct v2r0_disk_dqblk *d = dp;
    243	struct mem_dqblk *m = &dquot->dq_dqb;
    244	struct qtree_mem_dqinfo *info =
    245			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
    246
    247	d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
    248	d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
    249	d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
    250	d->dqb_itime = cpu_to_le64(m->dqb_itime);
    251	d->dqb_bhardlimit = cpu_to_le32(v2_stoqb(m->dqb_bhardlimit));
    252	d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
    253	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
    254	d->dqb_btime = cpu_to_le64(m->dqb_btime);
    255	d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
    256	if (qtree_entry_unused(info, dp))
    257		d->dqb_itime = cpu_to_le64(1);
    258}
    259
    260static int v2r0_is_id(void *dp, struct dquot *dquot)
    261{
    262	struct v2r0_disk_dqblk *d = dp;
    263	struct qtree_mem_dqinfo *info =
    264			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
    265
    266	if (qtree_entry_unused(info, dp))
    267		return 0;
    268	return qid_eq(make_kqid(&init_user_ns, dquot->dq_id.type,
    269				le32_to_cpu(d->dqb_id)),
    270		      dquot->dq_id);
    271}
    272
    273static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
    274{
    275	struct v2r1_disk_dqblk *d = dp, empty;
    276	struct mem_dqblk *m = &dquot->dq_dqb;
    277
    278	m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
    279	m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
    280	m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
    281	m->dqb_itime = le64_to_cpu(d->dqb_itime);
    282	m->dqb_bhardlimit = v2_qbtos(le64_to_cpu(d->dqb_bhardlimit));
    283	m->dqb_bsoftlimit = v2_qbtos(le64_to_cpu(d->dqb_bsoftlimit));
    284	m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
    285	m->dqb_btime = le64_to_cpu(d->dqb_btime);
    286	/* We need to escape back all-zero structure */
    287	memset(&empty, 0, sizeof(struct v2r1_disk_dqblk));
    288	empty.dqb_itime = cpu_to_le64(1);
    289	if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk)))
    290		m->dqb_itime = 0;
    291}
    292
    293static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
    294{
    295	struct v2r1_disk_dqblk *d = dp;
    296	struct mem_dqblk *m = &dquot->dq_dqb;
    297	struct qtree_mem_dqinfo *info =
    298			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
    299
    300	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
    301	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
    302	d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
    303	d->dqb_itime = cpu_to_le64(m->dqb_itime);
    304	d->dqb_bhardlimit = cpu_to_le64(v2_stoqb(m->dqb_bhardlimit));
    305	d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
    306	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
    307	d->dqb_btime = cpu_to_le64(m->dqb_btime);
    308	d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
    309	d->dqb_pad = 0;
    310	if (qtree_entry_unused(info, dp))
    311		d->dqb_itime = cpu_to_le64(1);
    312}
    313
    314static int v2r1_is_id(void *dp, struct dquot *dquot)
    315{
    316	struct v2r1_disk_dqblk *d = dp;
    317	struct qtree_mem_dqinfo *info =
    318			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
    319
    320	if (qtree_entry_unused(info, dp))
    321		return 0;
    322	return qid_eq(make_kqid(&init_user_ns, dquot->dq_id.type,
    323				le32_to_cpu(d->dqb_id)),
    324		      dquot->dq_id);
    325}
    326
    327static int v2_read_dquot(struct dquot *dquot)
    328{
    329	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
    330	int ret;
    331
    332	down_read(&dqopt->dqio_sem);
    333	ret = qtree_read_dquot(
    334			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
    335			dquot);
    336	up_read(&dqopt->dqio_sem);
    337	return ret;
    338}
    339
    340static int v2_write_dquot(struct dquot *dquot)
    341{
    342	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
    343	int ret;
    344	bool alloc = false;
    345
    346	/*
    347	 * If space for dquot is already allocated, we don't need any
    348	 * protection as we'll only overwrite the place of dquot. We are
    349	 * still protected by concurrent writes of the same dquot by
    350	 * dquot->dq_lock.
    351	 */
    352	if (!dquot->dq_off) {
    353		alloc = true;
    354		down_write(&dqopt->dqio_sem);
    355	} else {
    356		down_read(&dqopt->dqio_sem);
    357	}
    358	ret = qtree_write_dquot(
    359			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
    360			dquot);
    361	if (alloc)
    362		up_write(&dqopt->dqio_sem);
    363	else
    364		up_read(&dqopt->dqio_sem);
    365	return ret;
    366}
    367
    368static int v2_release_dquot(struct dquot *dquot)
    369{
    370	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
    371	int ret;
    372
    373	down_write(&dqopt->dqio_sem);
    374	ret = qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
    375	up_write(&dqopt->dqio_sem);
    376
    377	return ret;
    378}
    379
    380static int v2_free_file_info(struct super_block *sb, int type)
    381{
    382	kfree(sb_dqinfo(sb, type)->dqi_priv);
    383	return 0;
    384}
    385
    386static int v2_get_next_id(struct super_block *sb, struct kqid *qid)
    387{
    388	struct quota_info *dqopt = sb_dqopt(sb);
    389	int ret;
    390
    391	down_read(&dqopt->dqio_sem);
    392	ret = qtree_get_next_id(sb_dqinfo(sb, qid->type)->dqi_priv, qid);
    393	up_read(&dqopt->dqio_sem);
    394	return ret;
    395}
    396
    397static const struct quota_format_ops v2_format_ops = {
    398	.check_quota_file	= v2_check_quota_file,
    399	.read_file_info		= v2_read_file_info,
    400	.write_file_info	= v2_write_file_info,
    401	.free_file_info		= v2_free_file_info,
    402	.read_dqblk		= v2_read_dquot,
    403	.commit_dqblk		= v2_write_dquot,
    404	.release_dqblk		= v2_release_dquot,
    405	.get_next_id		= v2_get_next_id,
    406};
    407
    408static struct quota_format_type v2r0_quota_format = {
    409	.qf_fmt_id	= QFMT_VFS_V0,
    410	.qf_ops		= &v2_format_ops,
    411	.qf_owner	= THIS_MODULE
    412};
    413
    414static struct quota_format_type v2r1_quota_format = {
    415	.qf_fmt_id	= QFMT_VFS_V1,
    416	.qf_ops		= &v2_format_ops,
    417	.qf_owner	= THIS_MODULE
    418};
    419
    420static int __init init_v2_quota_format(void)
    421{
    422	int ret;
    423
    424	ret = register_quota_format(&v2r0_quota_format);
    425	if (ret)
    426		return ret;
    427	return register_quota_format(&v2r1_quota_format);
    428}
    429
    430static void __exit exit_v2_quota_format(void)
    431{
    432	unregister_quota_format(&v2r0_quota_format);
    433	unregister_quota_format(&v2r1_quota_format);
    434}
    435
    436module_init(init_v2_quota_format);
    437module_exit(exit_v2_quota_format);