aboutsummaryrefslogtreecommitdiffstats
ModeNameSize
-rw-r--r--.gitignore867logstatsplainblame
-rw-r--r--.mailmap3696logstatsplainblame
-rw-r--r--COPYING18693logstatsplainblame
-rw-r--r--CREDITS92729logstatsplainblame
d---------Documentation8114logstatsplain
-rw-r--r--Kbuild2465logstatsplainblame
-rw-r--r--MAINTAINERS102019logstatsplainblame
-rw-r--r--Makefile55659logstatsplainblame
-rw-r--r--README16930logstatsplainblame
-rw-r--r--REPORTING-BUGS3172logstatsplainblame
d---------arch805logstatsplain
d---------block1008logstatsplain
d---------crypto2544logstatsplain
d---------drivers2534logstatsplain
d---------firmware1006logstatsplain
d---------fs4810logstatsplain
d---------include1401logstatsplain
d---------init469logstatsplain
d---------ipc474logstatsplain
d---------kernel4411logstatsplain
d---------lib3957logstatsplain
d---------mm2173logstatsplain
d---------net1576logstatsplain
d---------samples214logstatsplain
d---------scripts2164logstatsplain
d---------security402logstatsplain
d---------sound782logstatsplain
d---------usr196logstatsplain
d---------virt / kvm30logstatsplain
'n545' href='#n545'>545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
/*
 *	vfsv0 quota IO operations on file
 */

#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/dqblk_v2.h>
#include <linux/quotaio_v2.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>

#include <asm/byteorder.h>

MODULE_AUTHOR("Jan Kara");
MODULE_DESCRIPTION("Quota format v2 support");
MODULE_LICENSE("GPL");

#define __QUOTA_V2_PARANOIA

typedef char *dqbuf_t;

#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))

/* Check whether given file is really vfsv0 quotafile */
static int v2_check_quota_file(struct super_block *sb, int type)
{
	struct v2_disk_dqheader dqhead;
	ssize_t size;
	static const uint quota_magics[] = V2_INITQMAGICS;
	static const uint quota_versions[] = V2_INITQVERSIONS;
 
	size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
	if (size != sizeof(struct v2_disk_dqheader)) {
		printk("quota_v2: failed read expected=%zd got=%zd\n",
			sizeof(struct v2_disk_dqheader), size);
		return 0;
	}
	if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
	    le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
		return 0;
	return 1;
}

/* Read information header from quota file */
static int v2_read_file_info(struct super_block *sb, int type)
{
	struct v2_disk_dqinfo dinfo;
	struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
	ssize_t size;

	size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
	       sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
	if (size != sizeof(struct v2_disk_dqinfo)) {
		printk(KERN_WARNING "Can't read info structure on device %s.\n",
			sb->s_id);
		return -1;
	}
	info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
	info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
	info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
	info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
	info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
	info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
	return 0;
}

/* Write information header to quota file */
static int v2_write_file_info(struct super_block *sb, int type)
{
	struct v2_disk_dqinfo dinfo;
	struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
	ssize_t size;

	spin_lock(&dq_data_lock);
	info->dqi_flags &= ~DQF_INFO_DIRTY;
	dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
	dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
	dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
	spin_unlock(&dq_data_lock);
	dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
	dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
	dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
	size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
	       sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
	if (size != sizeof(struct v2_disk_dqinfo)) {
		printk(KERN_WARNING "Can't write info structure on device %s.\n",
			sb->s_id);
		return -1;
	}
	return 0;
}

static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
{
	m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
	m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
	m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
	m->dqb_itime = le64_to_cpu(d->dqb_itime);
	m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
	m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
	m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
	m->dqb_btime = le64_to_cpu(d->dqb_btime);
}

static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
{
	d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
	d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
	d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
	d->dqb_itime = cpu_to_le64(m->dqb_itime);
	d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
	d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
	d->dqb_btime = cpu_to_le64(m->dqb_btime);
	d->dqb_id = cpu_to_le32(id);
}

static dqbuf_t getdqbuf(void)
{
	dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_NOFS);
	if (!buf)
		printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
	return buf;
}

static inline void freedqbuf(dqbuf_t buf)
{
	kfree(buf);
}

static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
{
	memset(buf, 0, V2_DQBLKSIZE);
	return sb->s_op->quota_read(sb, type, (char *)buf,
	       V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
}

static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
{
	return sb->s_op->quota_write(sb, type, (char *)buf,
	       V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
}

/* Remove empty block from list and return it */
static int get_free_dqblk(struct super_block *sb, int type)
{
	dqbuf_t buf = getdqbuf();
	struct mem_dqinfo *info = sb_dqinfo(sb, type);
	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
	int ret, blk;

	if (!buf)
		return -ENOMEM;
	if (info->u.v2_i.dqi_free_blk) {
		blk = info->u.v2_i.dqi_free_blk;
		if ((ret = read_blk(sb, type, blk, buf)) < 0)
			goto out_buf;
		info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
	}
	else {
		memset(buf, 0, V2_DQBLKSIZE);
		/* Assure block allocation... */
		if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0)
			goto out_buf;
		blk = info->u.v2_i.dqi_blocks++;
	}
	mark_info_dirty(sb, type);
	ret = blk;