public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Quota & XFS patch
@ 2002-02-27 16:09 Jan Kara
  2002-02-27 16:42 ` Alexander Viro
  2002-02-27 19:16 ` Shawn Starr
  0 siblings, 2 replies; 4+ messages in thread
From: Jan Kara @ 2002-02-27 16:09 UTC (permalink / raw)
  To: Alan Cox; +Cc: Nathan Scott, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 291 bytes --]

  Hello,

  I'm sending you Nathan's patch which implements things
in quotactl interface needed for XFS. If you can remember
the patch was already floating around some time
ago and was generally accepted... Please apply (it will
at least simplify patching of kernels for XFS).

							Honza

[-- Attachment #2: 2.4.18-pre3-ac2-quotactl.patch --]
[-- Type: text/plain, Size: 28380 bytes --]

diff -Naur 2.4.18-pre3-ac2/fs/Makefile 2.4.18-pre3-ac2-quotactl/fs/Makefile
--- 2.4.18-pre3-ac2/fs/Makefile	Tue Nov 13 04:34:16 2001
+++ 2.4.18-pre3-ac2-quotactl/fs/Makefile	Wed Jan 23 14:31:36 2002
@@ -14,12 +14,10 @@
 		super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
 		fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
-		filesystems.o namespace.o seq_file.o
+		filesystems.o namespace.o seq_file.o quota.o
 
 ifeq ($(CONFIG_QUOTA),y)
 obj-y += dquot.o
-else
-obj-y += noquot.o
 endif
 
 subdir-$(CONFIG_PROC_FS)	+= proc
diff -Naur 2.4.18-pre3-ac2/fs/dquot.c 2.4.18-pre3-ac2-quotactl/fs/dquot.c
--- 2.4.18-pre3-ac2/fs/dquot.c	Wed Jan 23 12:24:44 2002
+++ 2.4.18-pre3-ac2-quotactl/fs/dquot.c	Wed Jan 23 14:25:17 2002
@@ -46,9 +46,12 @@
  *		Jan Kara <jack@suse.cz> 12/2000
  *
  *		New quotafile format
- *		Alocation units changed to bytes
+ *		Allocation units changed to bytes
  *		Jan Kara, <jack@suse.cz>, 2000
  *
+ *		Reworked the quotactl interface for filesystem-specific quota
+ *		Nathan Scott <nathans@sgi.com> and Jan Kara <jack@suse.cz>, 2001
+ *
  * (C) Copyright 1994 - 1997 Marco van Wieringen 
  */
 
@@ -65,6 +68,7 @@
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/proc_fs.h>
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
@@ -73,8 +77,6 @@
 #define __DQUOT_NUM_VERSION__	(6*10000+5*100+0)
 #define __DQUOT_PARANOIA
 
-int nr_dquots, nr_free_dquots;
-
 static const char *quotatypes[] = INITQFNAMES;
 static const uint quota_magics[] = INITQMAGICS;
 static const uint quota_versions[] = INITQVERSIONS;
@@ -1004,6 +1006,11 @@
 	return 0;
 }
 
+static int quota_sync(struct super_block *sb, short type)
+{
+	return sync_dquots(sb->s_dev, type);
+}
+
 /* Free unused dquots from cache */
 static void prune_dqcache(int count)
 {
@@ -1466,35 +1473,30 @@
  * Initialize a dquot-struct with new quota info. This is used by the
  * system call interface functions.
  */ 
-static int set_dqblk(struct super_block *sb, qid_t id, short type, int flags, struct mem_dqblk *dqblk)
+static int set_dqblk(struct super_block *sb, short type, qid_t id, struct mem_dqblk *dqblk, int op)
 {
 	struct dquot *dquot;
-	int error = -EFAULT;
-	struct mem_dqblk dq_dqblk;
-
-	if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct mem_dqblk)))
-		return error;
 
-	if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) {
+	if ((dquot = dqget(sb, id, type)) != NODQUOT) {
 		/* We can't block while changing quota structure... */
-		if ((flags & SET_QUOTA) || (flags & SET_QLIMIT)) {
-			dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit;
-			dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit;
-			dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit;
-			dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit;
+		if (op == Q_SETQUOTA || op == Q_SETQLIM) {
+			dquot->dq_bhardlimit = dqblk->dqb_bhardlimit;
+			dquot->dq_bsoftlimit = dqblk->dqb_bsoftlimit;
+			dquot->dq_ihardlimit = dqblk->dqb_ihardlimit;
+			dquot->dq_isoftlimit = dqblk->dqb_isoftlimit;
 		}
 
-		if ((flags & SET_QUOTA) || (flags & SET_USE)) {
+		if (op == Q_SETQUOTA || op == Q_SETUSE) {
 			if (dquot->dq_isoftlimit &&
 			    dquot->dq_curinodes < dquot->dq_isoftlimit &&
-			    dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit)
+			    dqblk->dqb_curinodes >= dquot->dq_isoftlimit)
 				dquot->dq_itime = CURRENT_TIME + (__kernel_time_t)(sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace);
-			dquot->dq_curinodes = dq_dqblk.dqb_curinodes;
+			dquot->dq_curinodes = dqblk->dqb_curinodes;
 			if (dquot->dq_bsoftlimit &&
 			    toqb(dquot->dq_curspace) < dquot->dq_bsoftlimit &&
-			    toqb(dq_dqblk.dqb_curspace) >= dquot->dq_bsoftlimit)
+			    toqb(dqblk->dqb_curspace) >= dquot->dq_bsoftlimit)
 				dquot->dq_btime = CURRENT_TIME + (__kernel_time_t)(sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace);
-			dquot->dq_curspace = dq_dqblk.dqb_curspace;
+			dquot->dq_curspace = dqblk->dqb_curspace;
 		}
 
 		if (dquot->dq_curinodes < dquot->dq_isoftlimit || !dquot->dq_isoftlimit) {
@@ -1506,8 +1508,8 @@
 			dquot->dq_flags &= ~DQ_BLKS;
 		}
 
-		if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 &&
-		    dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0)
+		if (dqblk->dqb_bhardlimit == 0 && dqblk->dqb_bsoftlimit == 0 &&
+		    dqblk->dqb_ihardlimit == 0 && dqblk->dqb_isoftlimit == 0)
 			dquot->dq_flags |= DQ_FAKE;
 		else
 			dquot->dq_flags &= ~DQ_FAKE;
@@ -1518,79 +1520,86 @@
 	return 0;
 }
 
-static int get_quota(struct super_block *sb, qid_t id, short type, struct mem_dqblk *dqblk)
+static int get_dqblk(struct super_block *sb, short type, qid_t id, struct mem_dqblk *dqblk)
 {
 	struct dquot *dquot;
-	struct mem_dqblk data;
 	int error = -ESRCH;
 
-	if (!sb || !sb_has_quota_enabled(sb, type))
+	if (!sb_has_quota_enabled(sb, type))
 		goto out;
 	dquot = dqget(sb, id, type);
 	if (dquot == NODQUOT)
 		goto out;
 
-	memcpy(&data, &dquot->dq_dqb, sizeof(struct mem_dqblk));        /* We copy data to preserve them from changing */
+	memcpy(dqblk, &dquot->dq_dqb, sizeof(struct mem_dqblk));        /* We copy data to preserve them from changing */
 	dqput(dquot);
-	error = -EFAULT;
-	if (dqblk && !copy_to_user(dqblk, &data, sizeof(struct mem_dqblk)))
-		error = 0;
+	error = 0;
 out:
 	return error;
 }
 
-static int get_stats(caddr_t addr)
+#ifdef CONFIG_PROC_FS
+static int read_stats(char *buffer, char **start, off_t offset, int count, int *eof, void *data)
 {
-	int error = -EFAULT;
-	struct dqstats stats;
+	int len;
 
 	dqstats.allocated_dquots = nr_dquots;
 	dqstats.free_dquots = nr_free_dquots;
 
-	/* make a copy, in case we page-fault in user space */
-	memcpy(&stats, &dqstats, sizeof(struct dqstats));
-	if (!copy_to_user(addr, &stats, sizeof(struct dqstats)))
-		error = 0;
-	return error;
-}
+	len = sprintf(buffer, "Version %u\n", dqstats.version);
+	len += sprintf(buffer + len, "%u %u %u %u %u %u %u %u\n",
+			dqstats.lookups, dqstats.drops,
+			dqstats.reads, dqstats.writes,
+			dqstats.cache_hits, dqstats.allocated_dquots,
+			dqstats.free_dquots, dqstats.syncs);
+
+	if (offset >= len) {
+		*start = buffer;
+		*eof = 1;
+		return 0;
+	}
+	*start = buffer + offset;
+	if ((len -= offset) > count)
+		return count;
+	*eof = 1;
+
+	return len;
+}
+#define quota_proc_init()	\
+	create_proc_read_entry("fs/quota", 0, 0, read_stats, NULL);
+#else
+#define quota_proc_init()	do { } while (0)
+#endif
 
-static int get_info(struct super_block *sb, short type, struct mem_dqinfo *pinfo)
+static int get_info(struct super_block *sb, short type, struct mem_dqinfo *kinfo)
 {
-	struct mem_dqinfo kinfo;
-	
-	if (!sb || !sb_has_quota_enabled(sb, type))
+	if (!sb_has_quota_enabled(sb, type))
 		return -ESRCH;
 	/* Make our own copy so we can guarantee consistent structure */
-	memcpy(&kinfo, sb_dqopt(sb)->info+type, sizeof(struct mem_dqinfo));
-	kinfo.dqi_flags &= DQF_MASK;
-	if (copy_to_user(pinfo, &kinfo, sizeof(struct mem_dqinfo)))
-		return -EFAULT;
+	memcpy(kinfo, sb_dqopt(sb)->info+type, sizeof(struct mem_dqinfo));
+	kinfo->dqi_flags &= DQF_MASK;
 	return 0;
 }
 
-static int set_info(int op, struct super_block *sb, short type, struct mem_dqinfo *pinfo)
+static int set_info(struct super_block *sb, short type, struct mem_dqinfo *pinfo, int op)
 {
-	struct mem_dqinfo info;
 	struct quota_info *dqopt = sb_dqopt(sb);
 
-	if (!sb || !sb_has_quota_enabled(sb, type))
+	if (!sb_has_quota_enabled(sb, type))
 		return -ESRCH;
 
-	if (copy_from_user(&info, pinfo, sizeof(struct mem_dqinfo)))
-		return -EFAULT;
-	
 	switch (op) {
-		case ISET_FLAGS:
+		case Q_SETFLAGS:
 			dqopt->info[type].dqi_flags = (dqopt->info[type].dqi_flags & ~DQF_MASK)
-			  | (info.dqi_flags & DQF_MASK);
+			  | (pinfo->dqi_flags & DQF_MASK);
 			break;
-		case ISET_GRACE:
-			dqopt->info[type].dqi_bgrace = info.dqi_bgrace;
-			dqopt->info[type].dqi_igrace = info.dqi_igrace;
+		case Q_SETGRACE:
+			dqopt->info[type].dqi_bgrace = pinfo->dqi_bgrace;
+			dqopt->info[type].dqi_igrace = pinfo->dqi_igrace;
 			break;
-		case ISET_ALL:
-			info.dqi_flags &= ~DQF_MASK;
-			memcpy(dqopt->info + type, &info, sizeof(struct mem_dqinfo));
+		case Q_SETINFO:
+			pinfo->dqi_flags &= ~DQF_MASK;
+			memcpy(dqopt->info + type, pinfo, sizeof(struct mem_dqinfo));
 			break;
  	}
 	mark_quotafile_info_dirty(dqopt->info + type);
@@ -1875,6 +1884,7 @@
 		INIT_LIST_HEAD(dquot_hash + i);
 	dqstats.version = __DQUOT_NUM_VERSION__;
 	printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__);
+	quota_proc_init();
 	return 0;
 }
 __initcall(dquot_init);
@@ -1929,8 +1939,6 @@
 	struct quota_info *dqopt = sb_dqopt(sb);
 
 	lock_kernel();
-	if (!sb)
-		goto out;
 
 	/* We need to serialize quota_off() for device */
 	down(&dqopt->dqoff_sem);
@@ -1953,7 +1961,6 @@
 		fput(filp);
 	}	
 	up(&dqopt->dqoff_sem);
-out:
 	unlock_kernel();
 	return 0;
 }
@@ -2035,117 +2042,14 @@
 }
 
 /*
- * This is the system call interface. This communicates with
- * the user-level programs. Currently this only supports diskquota
- * calls. Maybe we need to add the process quotas etc. in the future,
- * but we probably should use rlimits for that.
+ * Definitions of quota operations accessible through quotactl(2).
  */
-asmlinkage long sys_quotactl(int cmd, const char *special, qid_t id, __kernel_caddr_t addr)
-{
-	int cmds = 0, type = 0, flags = 0;
-	kdev_t dev;
-	struct super_block *sb = NULL;
-	int ret = -EINVAL;
-
-	lock_kernel();
-	cmds = cmd >> SUBCMDSHIFT;
-	type = cmd & SUBCMDMASK;
-
-	if ((u_int) type >= MAXQUOTAS)
-		goto out;
-	if (id & ~0xFFFF)
-		goto out;
- 	if ((uint) type >= MAXQUOTAS || cmds > 0x1100 || cmds < 0x100 || cmds == 0x0300 ||
- 	    cmds == 0x0400 || cmds == 0x0500 || cmds == 0x1000)
-		goto out;
-
-	ret = -EPERM;
-	switch (cmds) {
-		case Q_SYNC:
-		case Q_GETSTATS:
-		case Q_GETINFO:
-			break;
-		case Q_GETQUOTA:
-			if (((type == USRQUOTA && current->euid != id) ||
-			     (type == GRPQUOTA && !in_egroup_p(id))) &&
-			    !capable(CAP_SYS_ADMIN))
-				goto out;
-			break;
-		default:
-			if (!capable(CAP_SYS_ADMIN))
-				goto out;
-	}
-
-	dev = NODEV;
-	if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) {
-		mode_t mode;
-		struct nameidata nd;
-
-		ret = user_path_walk(special, &nd);
-		if (ret)
-			goto out;
-
-		dev = nd.dentry->d_inode->i_rdev;
-		mode = nd.dentry->d_inode->i_mode;
-		path_release(&nd);
-
-		ret = -ENOTBLK;
-		if (!S_ISBLK(mode))
-			goto out;
-		ret = -ENODEV;
-		sb = get_super(dev);
-		if (!sb)
-			goto out;
-	}
-
-	ret = -EINVAL;
-	switch (cmds) {
-		case Q_QUOTAON:
-			ret = quota_on(sb, type, (char *) addr);
-			goto out;
-		case Q_QUOTAOFF:
-			ret = quota_off(sb, type);
-			goto out;
-		case Q_GETQUOTA:
-			ret = get_quota(sb, id, type, (struct mem_dqblk *) addr);
-			goto out;
-		case Q_SETQUOTA:
-			flags |= SET_QUOTA;
-			break;
-		case Q_SETUSE:
-			flags |= SET_USE;
-			break;
-		case Q_SETQLIM:
-			flags |= SET_QLIMIT;
-			break;
-		case Q_SYNC:
-			ret = sync_dquots(dev, type);
-			goto out;
-		case Q_GETSTATS:
-			ret = get_stats(addr);
-			goto out;
-		case Q_GETINFO:
-			ret = get_info(sb, type, (struct mem_dqinfo *) addr);
-			goto out;
-		case Q_SETFLAGS:
-			ret = set_info(ISET_FLAGS, sb, type, (struct mem_dqinfo *)addr);
-			goto out;
-		case Q_SETGRACE:
-			ret = set_info(ISET_GRACE, sb, type, (struct mem_dqinfo *)addr);
-			goto out;
-		case Q_SETINFO:
-			ret = set_info(ISET_ALL, sb, type, (struct mem_dqinfo *)addr);
- 			goto out;
-		default:
-			goto out;
-	}
-
-	ret = -NODEV;
-	if (sb && sb_has_quota_enabled(sb, type))
-		ret = set_dqblk(sb, id, type, flags, (struct mem_dqblk *) addr);
-out:
-	if (sb)
-		drop_super(sb);
-	unlock_kernel();
-	return ret;
-}
+struct quota_operations generic_quota_ops = {
+	quotaon:	quota_on,
+	quotaoff:	quota_off,
+	quotasync:	quota_sync,
+	getinfo:	get_info,
+	setinfo:	set_info,
+	getdqblk:	get_dqblk,
+	setdqblk:	set_dqblk,
+};
diff -Naur 2.4.18-pre3-ac2/fs/noquot.c 2.4.18-pre3-ac2-quotactl/fs/noquot.c
--- 2.4.18-pre3-ac2/fs/noquot.c	Sat May 13 04:21:20 2000
+++ 2.4.18-pre3-ac2-quotactl/fs/noquot.c	Thu Jan  1 10:00:00 1970
@@ -1,15 +0,0 @@
-/* noquot.c: Quota stubs necessary for when quotas are not
- *           compiled into the kernel.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-
-int nr_dquots, nr_free_dquots;
-int max_dquots;
-
-asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
-{
-	return(-ENOSYS);
-}
diff -Naur 2.4.18-pre3-ac2/fs/quota.c 2.4.18-pre3-ac2-quotactl/fs/quota.c
--- 2.4.18-pre3-ac2/fs/quota.c	Thu Jan  1 10:00:00 1970
+++ 2.4.18-pre3-ac2-quotactl/fs/quota.c	Wed Jan 23 15:08:49 2002
@@ -0,0 +1,204 @@
+/*
+ * Quota code necessary even when VFS quota support is not compiled
+ * into the kernel.  The interesting stuff is over in dquot.c, here
+ * we have symbols for initial quotactl(2) handling, the sysctl(2)
+ * variables, etc - things needed even when quota support disabled.
+ */
+
+#include <linux/fs.h>
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+
+int nr_dquots, nr_free_dquots;
+
+static struct super_block *
+validate_quotactl(int cmd, int type, const char *special, qid_t id)
+{
+	int ret;
+	kdev_t dev;
+	mode_t mode;
+	struct nameidata nd;
+	struct super_block *sb;
+
+	ret = -ENOSYS;
+	if (cmd == 0x0800 || cmd == 0x1100)	/* both were Q_GETSTATS */
+		goto error;
+
+	/* version/compatibility stuff - needs to be early on in the piece */
+	ret = -EINVAL;
+	if (cmd == 0x0300 || cmd == 0x0400 || cmd == 0x0500 || cmd == 0x1000
+	    || cmd < 0x100)
+		goto error;
+	if (type >= MAXQUOTAS)
+		goto error;
+
+	ret = -EPERM;
+	switch (cmd) {
+		case Q_SYNC:
+		case Q_GETINFO:
+		case Q_XGETQSTAT:
+			break;
+
+		case Q_GETQUOTA:
+		case Q_XGETQUOTA:
+			if (((type == USRQUOTA && current->euid != id) ||
+			     (type == GRPQUOTA && !in_egroup_p(id))) &&
+			    !capable(CAP_SYS_ADMIN))
+				goto error;
+
+		default:
+			if (!capable(CAP_SYS_ADMIN))
+				goto error;
+	}
+
+	ret = -ENODEV;
+	if (!special)
+		goto error;
+	ret = user_path_walk(special, &nd);
+	if (ret)
+		goto error;
+
+	dev = nd.dentry->d_inode->i_rdev;
+	mode = nd.dentry->d_inode->i_mode;
+	path_release(&nd);
+
+	ret = -ENOTBLK;
+	if (!S_ISBLK(mode))
+		goto error;
+
+	ret = -ENODEV;
+	sb = get_super(dev);
+	if (!sb)
+		goto error;
+
+	ret = -ENOSYS;
+	if (!sb->s_qop) {
+		drop_super(sb);
+		goto error;
+	}
+
+	return sb;
+error:
+	return ERR_PTR(ret);
+}
+
+asmlinkage long
+sys_quotactl(int cmd, const char *special, qid_t id, __kernel_caddr_t addr)
+{
+	int ret, cmds, type;
+	struct super_block *sb;
+	union {
+		char *pathname;
+		unsigned int flags;
+		struct mem_dqblk mdq;
+		struct mem_dqinfo info;
+		struct fs_disk_quota fdq;
+		struct fs_quota_stat fqs;
+	} u;  /* qualifies valid uses of "addr" */
+
+	lock_kernel();
+	cmds = cmd >> SUBCMDSHIFT;
+	type = cmd & SUBCMDMASK;
+
+	sb = validate_quotactl(cmds, type, special, id);
+	if (IS_ERR(sb)) {
+		unlock_kernel();
+		return PTR_ERR(sb);
+	}
+
+	ret = -EINVAL;
+	switch (cmds) {
+		case Q_QUOTAON:
+			u.pathname = (char *)addr;
+			if (sb->s_qop->quotaon)
+				ret = sb->s_qop->quotaon(sb, type, u.pathname);
+			break;
+
+		case Q_QUOTAOFF:
+			if (sb->s_qop->quotaoff)
+				ret = sb->s_qop->quotaoff(sb, type);
+			break;
+
+	    	case Q_SYNC:
+			if (sb->s_qop->quotasync)
+				ret = sb->s_qop->quotasync(sb, type);
+			break;
+
+		case Q_GETINFO:
+			if (sb->s_qop->getinfo)
+				ret = sb->s_qop->getinfo(sb, type, &u.info);
+			if (!ret && copy_to_user(addr, &u.info, sizeof(u.info)))
+				ret = -EFAULT;
+			break;
+
+		case Q_SETINFO:
+		case Q_SETFLAGS:
+		case Q_SETGRACE:
+			if (!sb->s_qop->setinfo)
+				break;
+			ret = -EFAULT;
+			if (copy_from_user(&u.info, addr, sizeof(u.info)))
+				break;
+			ret = sb->s_qop->setinfo(sb, type, &u.info, cmds);
+			break;
+
+		case Q_GETQUOTA:
+			if (sb->s_qop->getdqblk)
+				ret = sb->s_qop->getdqblk(sb, type, id, &u.mdq);
+			if (!ret && copy_to_user(addr, &u.mdq, sizeof(u.mdq)))
+				ret = -EFAULT;
+			break;
+
+		case Q_SETUSE:
+		case Q_SETQLIM:
+		case Q_SETQUOTA:
+			if (!sb->s_qop->setdqblk)
+				break;
+			ret = -EFAULT;
+			if (copy_from_user(&u.mdq, addr, sizeof(u.mdq)))
+				break;
+			ret = sb->s_qop->setdqblk(sb, type, id, &u.mdq, cmds);
+			break;
+
+		case Q_XQUOTAON:
+		case Q_XQUOTAOFF:
+		case Q_XQUOTARM:
+			if (!sb->s_qop->setxstate)
+				break;
+			ret = -EFAULT;
+			if (copy_from_user(&u.flags, addr, sizeof(u.flags)))
+				break;
+			ret = sb->s_qop->setxstate(sb, u.flags, cmds);
+			break;
+
+		case Q_XGETQSTAT:
+			if (sb->s_qop->getxstate)
+				ret = sb->s_qop->getxstate(sb, &u.fqs);
+			if (!ret && copy_to_user(addr, &u.fqs, sizeof(u.fqs)))
+				ret = -EFAULT;
+			break;
+
+		case Q_XSETQLIM:
+			if (!sb->s_qop->setxquota)
+				break;
+			ret = -EFAULT;
+			if (copy_from_user(&u.fdq, addr, sizeof(u.fdq)))
+				break;
+			ret = sb->s_qop->setxquota(sb, type, id, &u.fdq);
+			break;
+
+		case Q_XGETQUOTA:
+			if (sb->s_qop->getxquota)
+				ret = sb->s_qop->getxquota(sb, type, id, &u.fdq);
+			if (!ret && copy_to_user(addr, &u.fdq, sizeof(u.fdq)))
+				ret = -EFAULT;
+			break;
+
+		default:
+	}
+	drop_super(sb);
+	unlock_kernel();
+	return ret;
+}
diff -Naur 2.4.18-pre3-ac2/fs/super.c 2.4.18-pre3-ac2-quotactl/fs/super.c
--- 2.4.18-pre3-ac2/fs/super.c	Sat Dec 22 04:42:03 2001
+++ 2.4.18-pre3-ac2-quotactl/fs/super.c	Wed Jan 23 12:26:41 2002
@@ -437,6 +437,7 @@
 		sema_init(&s->s_dquot.dqio_sem, 1);
 		sema_init(&s->s_dquot.dqoff_sem, 1);
 		s->s_maxbytes = MAX_NON_LFS;
+		s->s_qop = sb_generic_quota_ops;
 	}
 	return s;
 }
diff -Naur 2.4.18-pre3-ac2/include/linux/fs.h 2.4.18-pre3-ac2-quotactl/include/linux/fs.h
--- 2.4.18-pre3-ac2/include/linux/fs.h	Wed Jan 23 12:24:44 2002
+++ 2.4.18-pre3-ac2-quotactl/include/linux/fs.h	Wed Jan 23 14:50:06 2002
@@ -365,6 +365,7 @@
 /*
  * Includes for diskquotas and mount structures.
  */
+#include <linux/xqm.h>
 #include <linux/quota.h>
 #include <linux/mount.h>
 
@@ -691,6 +692,20 @@
 	struct mem_dqinfo info[MAXQUOTAS];	/* Information for each quota type */
 };
 
+struct quota_operations {
+	int (*quotaon)(struct super_block *, short, char *);
+	int (*quotaoff)(struct super_block *, short);
+	int (*quotasync)(struct super_block *, short);
+	int (*getinfo)(struct super_block *, short, struct mem_dqinfo *);
+	int (*setinfo)(struct super_block *, short, struct mem_dqinfo *, int);
+	int (*getdqblk)(struct super_block *, short, qid_t, struct mem_dqblk *);
+	int (*setdqblk)(struct super_block *, short, qid_t, struct mem_dqblk *, int);
+	int (*getxstate)(struct super_block *, struct fs_quota_stat *);
+	int (*setxstate)(struct super_block *, unsigned int, int);
+	int (*getxquota)(struct super_block *, short, qid_t, struct fs_disk_quota *);
+	int (*setxquota)(struct super_block *, short, qid_t, struct fs_disk_quota *);
+};
+
 /*
  *	Umount options
  */
@@ -752,7 +767,8 @@
 
 	struct block_device	*s_bdev;
 	struct list_head	s_instances;
- 	struct quota_info s_dquot;	/* Diskquota specific options */
+ 	struct quota_info	s_dquot;	/* Diskquota specific options */
+	struct quota_operations	*s_qop;
 
 	union {
 		struct minix_sb_info	minix_sb;
diff -Naur 2.4.18-pre3-ac2/include/linux/quota.h 2.4.18-pre3-ac2-quotactl/include/linux/quota.h
--- 2.4.18-pre3-ac2/include/linux/quota.h	Wed Jan 23 12:24:44 2002
+++ 2.4.18-pre3-ac2-quotactl/include/linux/quota.h	Wed Jan 23 14:43:51 2002
@@ -107,7 +107,7 @@
 #define Q_SETQUOTA 0x0E00	/* set limits and usage */
 #define Q_SETUSE   0x0F00	/* set usage */
 /* 0x1000 used by old RSQUASH */
-#define Q_GETSTATS 0x1100	/* get collected stats */
+/* 0x1100 used by GETSTATS v2, since replaced by procfs entry */
 
 /*
  * The following structure defines the format of the disk quota file
@@ -255,13 +255,6 @@
 #define dq_btime dq_dqb.dqb_btime
 
 /*
- * Flags used for set_dqblk.
- */
-#define SET_QUOTA         0x01
-#define SET_USE           0x02
-#define SET_QLIMIT        0x04
-
-/*
  * Flags used for set_info
  */
 #define ISET_GRACE 0x01
diff -Naur 2.4.18-pre3-ac2/include/linux/quotaops.h 2.4.18-pre3-ac2-quotactl/include/linux/quotaops.h
--- 2.4.18-pre3-ac2/include/linux/quotaops.h	Wed Jan 23 12:24:44 2002
+++ 2.4.18-pre3-ac2-quotactl/include/linux/quotaops.h	Wed Jan 23 15:03:56 2002
@@ -17,6 +17,9 @@
 
 #include <linux/fs.h>
 
+extern struct quota_operations generic_quota_ops;
+#define sb_generic_quota_ops (&generic_quota_ops)
+
 /*
  * declaration of quota_function calls in kernel.
  */
@@ -167,6 +170,7 @@
 /*
  * NO-OP when quota not configured.
  */
+#define sb_generic_quota_ops			(NULL)
 #define DQUOT_INIT(inode)			do { } while(0)
 #define DQUOT_DROP(inode)			do { } while(0)
 #define DQUOT_ALLOC_INODE(inode)		(0)
diff -Naur 2.4.18-pre3-ac2/include/linux/sysctl.h 2.4.18-pre3-ac2-quotactl/include/linux/sysctl.h
--- 2.4.18-pre3-ac2/include/linux/sysctl.h	Wed Jan 23 12:24:44 2002
+++ 2.4.18-pre3-ac2-quotactl/include/linux/sysctl.h	Wed Jan 23 14:43:51 2002
@@ -533,7 +533,7 @@
 	FS_STATINODE=2,
 	FS_MAXINODE=3,	/* int:maximum number of inodes that can be allocated */
 	FS_NRDQUOT=4,	/* int:current number of allocated dquots */
-	FS_MAXDQUOT=5,	/* int:maximum number of dquots that can be allocated */
+	/* was FS_MAXDQUOT */
 	FS_NRFILE=6,	/* int:current number of allocated filedescriptors */
 	FS_MAXFILE=7,	/* int:maximum number of filedescriptors that can be allocated */
 	FS_DENTRY=8,
diff -Naur 2.4.18-pre3-ac2/include/linux/xqm.h 2.4.18-pre3-ac2-quotactl/include/linux/xqm.h
--- 2.4.18-pre3-ac2/include/linux/xqm.h	Thu Jan  1 10:00:00 1970
+++ 2.4.18-pre3-ac2-quotactl/include/linux/xqm.h	Wed Jan 23 14:43:51 2002
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 1995-2001 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef _LINUX_XQM_H
+#define _LINUX_XQM_H
+
+#include <linux/types.h>
+
+/*
+ * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM).
+ */
+
+#define XQM_CMD(x)	(('X'<<8)+(x))	/* note: forms first QCMD argument */
+#define Q_XQUOTAON	XQM_CMD(0x1)	/* enable accounting/enforcement */
+#define Q_XQUOTAOFF	XQM_CMD(0x2)	/* disable accounting/enforcement */
+#define Q_XGETQUOTA	XQM_CMD(0x3)	/* get disk limits and usage */
+#define Q_XSETQLIM	XQM_CMD(0x4)	/* set disk limits */
+#define Q_XGETQSTAT	XQM_CMD(0x5)	/* get quota subsystem status */
+#define Q_XQUOTARM	XQM_CMD(0x6)	/* free disk space used by dquots */
+
+/*
+ * fs_disk_quota structure:
+ *
+ * This contains the current quota information regarding a user/proj/group.
+ * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of
+ * 512 bytes.
+ */
+#define FS_DQUOT_VERSION	1	/* fs_disk_quota.d_version */
+typedef struct fs_disk_quota {
+	__s8		d_version;	/* version of this structure */
+	__s8		d_flags;	/* XFS_{USER,PROJ,GROUP}_QUOTA */
+	__u16		d_fieldmask;	/* field specifier */
+	__u32		d_id;		/* user, project, or group ID */
+	__u64		d_blk_hardlimit;/* absolute limit on disk blks */
+	__u64		d_blk_softlimit;/* preferred limit on disk blks */
+	__u64		d_ino_hardlimit;/* maximum # allocated inodes */
+	__u64		d_ino_softlimit;/* preferred inode limit */
+	__u64		d_bcount;	/* # disk blocks owned by the user */
+	__u64		d_icount;	/* # inodes owned by the user */
+	__s32		d_itimer;	/* zero if within inode limits */
+					/* if not, we refuse service */
+	__s32		d_btimer;	/* similar to above; for disk blocks */
+	__u16	  	d_iwarns;       /* # warnings issued wrt num inodes */
+	__u16	  	d_bwarns;       /* # warnings issued wrt disk blocks */
+	__s32		d_padding2;	/* padding2 - for future use */
+	__u64		d_rtb_hardlimit;/* absolute limit on realtime blks */
+	__u64		d_rtb_softlimit;/* preferred limit on RT disk blks */
+	__u64		d_rtbcount;	/* # realtime blocks owned */
+	__s32		d_rtbtimer;	/* similar to above; for RT disk blks */
+	__u16	  	d_rtbwarns;     /* # warnings issued wrt RT disk blks */
+	__s16		d_padding3;	/* padding3 - for future use */	
+	char		d_padding4[8];	/* yet more padding */
+} fs_disk_quota_t;
+
+/*
+ * These fields are sent to Q_XSETQLIM to specify fields that need to change.
+ */
+#define FS_DQ_ISOFT	(1<<0)
+#define FS_DQ_IHARD	(1<<1)
+#define FS_DQ_BSOFT	(1<<2)
+#define FS_DQ_BHARD 	(1<<3)
+#define FS_DQ_RTBSOFT	(1<<4)
+#define FS_DQ_RTBHARD	(1<<5)
+#define FS_DQ_LIMIT_MASK	(FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \
+				 FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD)
+/*
+ * These timers can only be set in super user's dquot. For others, timers are
+ * automatically started and stopped. Superusers timer values set the limits
+ * for the rest.  In case these values are zero, the DQ_{F,B}TIMELIMIT values
+ * defined below are used. 
+ * These values also apply only to the d_fieldmask field for Q_XSETQLIM.
+ */
+#define FS_DQ_BTIMER	(1<<6)
+#define FS_DQ_ITIMER	(1<<7)
+#define FS_DQ_RTBTIMER 	(1<<8)
+#define FS_DQ_TIMER_MASK	(FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER)
+
+/*
+ * The following constants define the default amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure).  These may be modified by the quotactl(2)
+ * system call with the Q_XSETQLIM command.
+ */
+#define	DQ_FTIMELIMIT	(7 * 24*60*60)		/* 1 week */
+#define	DQ_BTIMELIMIT	(7 * 24*60*60)		/* 1 week */
+
+/*
+ * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
+ */
+#define XFS_QUOTA_UDQ_ACCT	(1<<0)  /* user quota accounting */
+#define XFS_QUOTA_UDQ_ENFD	(1<<1)  /* user quota limits enforcement */
+#define XFS_QUOTA_GDQ_ACCT	(1<<2)  /* group quota accounting */
+#define XFS_QUOTA_GDQ_ENFD	(1<<3)  /* group quota limits enforcement */
+
+#define XFS_USER_QUOTA		(1<<0)	/* user quota type */
+#define XFS_PROJ_QUOTA		(1<<1)	/* (IRIX) project quota type */
+#define XFS_GROUP_QUOTA		(1<<2)	/* group quota type */
+
+/*
+ * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system.
+ * Provides a centralized way to get meta infomation about the quota subsystem.
+ * eg. space taken up for user and group quotas, number of dquots currently
+ * incore.
+ */
+#define FS_QSTAT_VERSION	1	/* fs_quota_stat.qs_version */
+
+/*
+ * Some basic infomation about 'quota files'.
+ */
+typedef struct fs_qfilestat {
+	__u64		qfs_ino;	/* inode number */
+	__u64		qfs_nblks;	/* number of BBs 512-byte-blks */
+	__u32		qfs_nextents;	/* number of extents */
+} fs_qfilestat_t;
+
+typedef struct fs_quota_stat {
+	__s8		qs_version;	/* version number for future changes */
+	__u16		qs_flags;	/* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
+	__s8		qs_pad;		/* unused */
+	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
+	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
+	__u32		qs_incoredqs;	/* number of dquots incore */
+	__s32		qs_btimelimit;  /* limit for blks timer */	
+	__s32		qs_itimelimit;  /* limit for inodes timer */	
+	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
+	__u16		qs_bwarnlimit;	/* limit for num warnings */
+	__u16		qs_iwarnlimit;	/* limit for num warnings */
+} fs_quota_stat_t;
+
+#endif	/* _LINUX_XQM_H */

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Quota & XFS patch
  2002-02-27 16:09 Quota & XFS patch Jan Kara
@ 2002-02-27 16:42 ` Alexander Viro
  2002-02-27 21:39   ` Jan Kara
  2002-02-27 19:16 ` Shawn Starr
  1 sibling, 1 reply; 4+ messages in thread
From: Alexander Viro @ 2002-02-27 16:42 UTC (permalink / raw)
  To: Jan Kara; +Cc: Alan Cox, Nathan Scott, linux-kernel



On Wed, 27 Feb 2002, Jan Kara wrote:

>   Hello,
> 
>   I'm sending you Nathan's patch which implements things
> in quotactl interface needed for XFS. If you can remember
> the patch was already floating around some time
> ago and was generally accepted... Please apply (it will
> at least simplify patching of kernels for XFS).

Why are you leaving some copy_from_user() in methods?  Either the structures
you are passing are fs-independent and everybody would be better off with
having them copied in one place or they are not, and then API is completely
broken.


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Quota & XFS patch
  2002-02-27 16:09 Quota & XFS patch Jan Kara
  2002-02-27 16:42 ` Alexander Viro
@ 2002-02-27 19:16 ` Shawn Starr
  1 sibling, 0 replies; 4+ messages in thread
From: Shawn Starr @ 2002-02-27 19:16 UTC (permalink / raw)
  To: Jan Kara; +Cc: Alan Cox, Nathan Scott, Linux

This is the latest one right? The one I see is 2.4.17-3 on the suse ftp
site.

On Wed, 2002-02-27 at 11:09, Jan Kara wrote:
>   Hello,
> 
>   I'm sending you Nathan's patch which implements things
> in quotactl interface needed for XFS. If you can remember
> the patch was already floating around some time
> ago and was generally accepted... Please apply (it will
> at least simplify patching of kernels for XFS).
> 
> 							Honza
> ----
> 

> diff -Naur 2.4.18-pre3-ac2/fs/Makefile 2.4.18-pre3-ac2-quotactl/fs/Makefile
> --- 2.4.18-pre3-ac2/fs/Makefile	Tue Nov 13 04:34:16 2001
> +++ 2.4.18-pre3-ac2-quotactl/fs/Makefile	Wed Jan 23 14:31:36 2002
> @@ -14,12 +14,10 @@
>  		super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
>  		fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
>  		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
> -		filesystems.o namespace.o seq_file.o
> +		filesystems.o namespace.o seq_file.o quota.o
>  
>  ifeq ($(CONFIG_QUOTA),y)
>  obj-y += dquot.o
> -else
> -obj-y += noquot.o
>  endif
>  
>  subdir-$(CONFIG_PROC_FS)	+= proc
> diff -Naur 2.4.18-pre3-ac2/fs/dquot.c 2.4.18-pre3-ac2-quotactl/fs/dquot.c
> --- 2.4.18-pre3-ac2/fs/dquot.c	Wed Jan 23 12:24:44 2002
> +++ 2.4.18-pre3-ac2-quotactl/fs/dquot.c	Wed Jan 23 14:25:17 2002
> @@ -46,9 +46,12 @@
>   *		Jan Kara <jack@suse.cz> 12/2000
>   *
>   *		New quotafile format
> - *		Alocation units changed to bytes
> + *		Allocation units changed to bytes
>   *		Jan Kara, <jack@suse.cz>, 2000
>   *
> + *		Reworked the quotactl interface for filesystem-specific quota
> + *		Nathan Scott <nathans@sgi.com> and Jan Kara <jack@suse.cz>, 2001
> + *
>   * (C) Copyright 1994 - 1997 Marco van Wieringen 
>   */
>  
> @@ -65,6 +68,7 @@
>  #include <linux/slab.h>
>  #include <linux/smp_lock.h>
>  #include <linux/init.h>
> +#include <linux/proc_fs.h>
>  
>  #include <asm/uaccess.h>
>  #include <asm/byteorder.h>
> @@ -73,8 +77,6 @@
>  #define __DQUOT_NUM_VERSION__	(6*10000+5*100+0)
>  #define __DQUOT_PARANOIA
>  
> -int nr_dquots, nr_free_dquots;
> -
>  static const char *quotatypes[] = INITQFNAMES;
>  static const uint quota_magics[] = INITQMAGICS;
>  static const uint quota_versions[] = INITQVERSIONS;
> @@ -1004,6 +1006,11 @@
>  	return 0;
>  }
>  
> +static int quota_sync(struct super_block *sb, short type)
> +{
> +	return sync_dquots(sb->s_dev, type);
> +}
> +
>  /* Free unused dquots from cache */
>  static void prune_dqcache(int count)
>  {
> @@ -1466,35 +1473,30 @@
>   * Initialize a dquot-struct with new quota info. This is used by the
>   * system call interface functions.
>   */ 
> -static int set_dqblk(struct super_block *sb, qid_t id, short type, int flags, struct mem_dqblk *dqblk)
> +static int set_dqblk(struct super_block *sb, short type, qid_t id, struct mem_dqblk *dqblk, int op)
>  {
>  	struct dquot *dquot;
> -	int error = -EFAULT;
> -	struct mem_dqblk dq_dqblk;
> -
> -	if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct mem_dqblk)))
> -		return error;
>  
> -	if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) {
> +	if ((dquot = dqget(sb, id, type)) != NODQUOT) {
>  		/* We can't block while changing quota structure... */
> -		if ((flags & SET_QUOTA) || (flags & SET_QLIMIT)) {
> -			dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit;
> -			dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit;
> -			dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit;
> -			dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit;
> +		if (op == Q_SETQUOTA || op == Q_SETQLIM) {
> +			dquot->dq_bhardlimit = dqblk->dqb_bhardlimit;
> +			dquot->dq_bsoftlimit = dqblk->dqb_bsoftlimit;
> +			dquot->dq_ihardlimit = dqblk->dqb_ihardlimit;
> +			dquot->dq_isoftlimit = dqblk->dqb_isoftlimit;
>  		}
>  
> -		if ((flags & SET_QUOTA) || (flags & SET_USE)) {
> +		if (op == Q_SETQUOTA || op == Q_SETUSE) {
>  			if (dquot->dq_isoftlimit &&
>  			    dquot->dq_curinodes < dquot->dq_isoftlimit &&
> -			    dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit)
> +			    dqblk->dqb_curinodes >= dquot->dq_isoftlimit)
>  				dquot->dq_itime = CURRENT_TIME + (__kernel_time_t)(sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace);
> -			dquot->dq_curinodes = dq_dqblk.dqb_curinodes;
> +			dquot->dq_curinodes = dqblk->dqb_curinodes;
>  			if (dquot->dq_bsoftlimit &&
>  			    toqb(dquot->dq_curspace) < dquot->dq_bsoftlimit &&
> -			    toqb(dq_dqblk.dqb_curspace) >= dquot->dq_bsoftlimit)
> +			    toqb(dqblk->dqb_curspace) >= dquot->dq_bsoftlimit)
>  				dquot->dq_btime = CURRENT_TIME + (__kernel_time_t)(sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace);
> -			dquot->dq_curspace = dq_dqblk.dqb_curspace;
> +			dquot->dq_curspace = dqblk->dqb_curspace;
>  		}
>  
>  		if (dquot->dq_curinodes < dquot->dq_isoftlimit || !dquot->dq_isoftlimit) {
> @@ -1506,8 +1508,8 @@
>  			dquot->dq_flags &= ~DQ_BLKS;
>  		}
>  
> -		if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 &&
> -		    dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0)
> +		if (dqblk->dqb_bhardlimit == 0 && dqblk->dqb_bsoftlimit == 0 &&
> +		    dqblk->dqb_ihardlimit == 0 && dqblk->dqb_isoftlimit == 0)
>  			dquot->dq_flags |= DQ_FAKE;
>  		else
>  			dquot->dq_flags &= ~DQ_FAKE;
> @@ -1518,79 +1520,86 @@
>  	return 0;
>  }
>  
> -static int get_quota(struct super_block *sb, qid_t id, short type, struct mem_dqblk *dqblk)
> +static int get_dqblk(struct super_block *sb, short type, qid_t id, struct mem_dqblk *dqblk)
>  {
>  	struct dquot *dquot;
> -	struct mem_dqblk data;
>  	int error = -ESRCH;
>  
> -	if (!sb || !sb_has_quota_enabled(sb, type))
> +	if (!sb_has_quota_enabled(sb, type))
>  		goto out;
>  	dquot = dqget(sb, id, type);
>  	if (dquot == NODQUOT)
>  		goto out;
>  
> -	memcpy(&data, &dquot->dq_dqb, sizeof(struct mem_dqblk));        /* We copy data to preserve them from changing */
> +	memcpy(dqblk, &dquot->dq_dqb, sizeof(struct mem_dqblk));        /* We copy data to preserve them from changing */
>  	dqput(dquot);
> -	error = -EFAULT;
> -	if (dqblk && !copy_to_user(dqblk, &data, sizeof(struct mem_dqblk)))
> -		error = 0;
> +	error = 0;
>  out:
>  	return error;
>  }
>  
> -static int get_stats(caddr_t addr)
> +#ifdef CONFIG_PROC_FS
> +static int read_stats(char *buffer, char **start, off_t offset, int count, int *eof, void *data)
>  {
> -	int error = -EFAULT;
> -	struct dqstats stats;
> +	int len;
>  
>  	dqstats.allocated_dquots = nr_dquots;
>  	dqstats.free_dquots = nr_free_dquots;
>  
> -	/* make a copy, in case we page-fault in user space */
> -	memcpy(&stats, &dqstats, sizeof(struct dqstats));
> -	if (!copy_to_user(addr, &stats, sizeof(struct dqstats)))
> -		error = 0;
> -	return error;
> -}
> +	len = sprintf(buffer, "Version %u\n", dqstats.version);
> +	len += sprintf(buffer + len, "%u %u %u %u %u %u %u %u\n",
> +			dqstats.lookups, dqstats.drops,
> +			dqstats.reads, dqstats.writes,
> +			dqstats.cache_hits, dqstats.allocated_dquots,
> +			dqstats.free_dquots, dqstats.syncs);
> +
> +	if (offset >= len) {
> +		*start = buffer;
> +		*eof = 1;
> +		return 0;
> +	}
> +	*start = buffer + offset;
> +	if ((len -= offset) > count)
> +		return count;
> +	*eof = 1;
> +
> +	return len;
> +}
> +#define quota_proc_init()	\
> +	create_proc_read_entry("fs/quota", 0, 0, read_stats, NULL);
> +#else
> +#define quota_proc_init()	do { } while (0)
> +#endif
>  
> -static int get_info(struct super_block *sb, short type, struct mem_dqinfo *pinfo)
> +static int get_info(struct super_block *sb, short type, struct mem_dqinfo *kinfo)
>  {
> -	struct mem_dqinfo kinfo;
> -	
> -	if (!sb || !sb_has_quota_enabled(sb, type))
> +	if (!sb_has_quota_enabled(sb, type))
>  		return -ESRCH;
>  	/* Make our own copy so we can guarantee consistent structure */
> -	memcpy(&kinfo, sb_dqopt(sb)->info+type, sizeof(struct mem_dqinfo));
> -	kinfo.dqi_flags &= DQF_MASK;
> -	if (copy_to_user(pinfo, &kinfo, sizeof(struct mem_dqinfo)))
> -		return -EFAULT;
> +	memcpy(kinfo, sb_dqopt(sb)->info+type, sizeof(struct mem_dqinfo));
> +	kinfo->dqi_flags &= DQF_MASK;
>  	return 0;
>  }
>  
> -static int set_info(int op, struct super_block *sb, short type, struct mem_dqinfo *pinfo)
> +static int set_info(struct super_block *sb, short type, struct mem_dqinfo *pinfo, int op)
>  {
> -	struct mem_dqinfo info;
>  	struct quota_info *dqopt = sb_dqopt(sb);
>  
> -	if (!sb || !sb_has_quota_enabled(sb, type))
> +	if (!sb_has_quota_enabled(sb, type))
>  		return -ESRCH;
>  
> -	if (copy_from_user(&info, pinfo, sizeof(struct mem_dqinfo)))
> -		return -EFAULT;
> -	
>  	switch (op) {
> -		case ISET_FLAGS:
> +		case Q_SETFLAGS:
>  			dqopt->info[type].dqi_flags = (dqopt->info[type].dqi_flags & ~DQF_MASK)
> -			  | (info.dqi_flags & DQF_MASK);
> +			  | (pinfo->dqi_flags & DQF_MASK);
>  			break;
> -		case ISET_GRACE:
> -			dqopt->info[type].dqi_bgrace = info.dqi_bgrace;
> -			dqopt->info[type].dqi_igrace = info.dqi_igrace;
> +		case Q_SETGRACE:
> +			dqopt->info[type].dqi_bgrace = pinfo->dqi_bgrace;
> +			dqopt->info[type].dqi_igrace = pinfo->dqi_igrace;
>  			break;
> -		case ISET_ALL:
> -			info.dqi_flags &= ~DQF_MASK;
> -			memcpy(dqopt->info + type, &info, sizeof(struct mem_dqinfo));
> +		case Q_SETINFO:
> +			pinfo->dqi_flags &= ~DQF_MASK;
> +			memcpy(dqopt->info + type, pinfo, sizeof(struct mem_dqinfo));
>  			break;
>   	}
>  	mark_quotafile_info_dirty(dqopt->info + type);
> @@ -1875,6 +1884,7 @@
>  		INIT_LIST_HEAD(dquot_hash + i);
>  	dqstats.version = __DQUOT_NUM_VERSION__;
>  	printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__);
> +	quota_proc_init();
>  	return 0;
>  }
>  __initcall(dquot_init);
> @@ -1929,8 +1939,6 @@
>  	struct quota_info *dqopt = sb_dqopt(sb);
>  
>  	lock_kernel();
> -	if (!sb)
> -		goto out;
>  
>  	/* We need to serialize quota_off() for device */
>  	down(&dqopt->dqoff_sem);
> @@ -1953,7 +1961,6 @@
>  		fput(filp);
>  	}	
>  	up(&dqopt->dqoff_sem);
> -out:
>  	unlock_kernel();
>  	return 0;
>  }
> @@ -2035,117 +2042,14 @@
>  }
>  
>  /*
> - * This is the system call interface. This communicates with
> - * the user-level programs. Currently this only supports diskquota
> - * calls. Maybe we need to add the process quotas etc. in the future,
> - * but we probably should use rlimits for that.
> + * Definitions of quota operations accessible through quotactl(2).
>   */
> -asmlinkage long sys_quotactl(int cmd, const char *special, qid_t id, __kernel_caddr_t addr)
> -{
> -	int cmds = 0, type = 0, flags = 0;
> -	kdev_t dev;
> -	struct super_block *sb = NULL;
> -	int ret = -EINVAL;
> -
> -	lock_kernel();
> -	cmds = cmd >> SUBCMDSHIFT;
> -	type = cmd & SUBCMDMASK;
> -
> -	if ((u_int) type >= MAXQUOTAS)
> -		goto out;
> -	if (id & ~0xFFFF)
> -		goto out;
> - 	if ((uint) type >= MAXQUOTAS || cmds > 0x1100 || cmds < 0x100 || cmds == 0x0300 ||
> - 	    cmds == 0x0400 || cmds == 0x0500 || cmds == 0x1000)
> -		goto out;
> -
> -	ret = -EPERM;
> -	switch (cmds) {
> -		case Q_SYNC:
> -		case Q_GETSTATS:
> -		case Q_GETINFO:
> -			break;
> -		case Q_GETQUOTA:
> -			if (((type == USRQUOTA && current->euid != id) ||
> -			     (type == GRPQUOTA && !in_egroup_p(id))) &&
> -			    !capable(CAP_SYS_ADMIN))
> -				goto out;
> -			break;
> -		default:
> -			if (!capable(CAP_SYS_ADMIN))
> -				goto out;
> -	}
> -
> -	dev = NODEV;
> -	if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) {
> -		mode_t mode;
> -		struct nameidata nd;
> -
> -		ret = user_path_walk(special, &nd);
> -		if (ret)
> -			goto out;
> -
> -		dev = nd.dentry->d_inode->i_rdev;
> -		mode = nd.dentry->d_inode->i_mode;
> -		path_release(&nd);
> -
> -		ret = -ENOTBLK;
> -		if (!S_ISBLK(mode))
> -			goto out;
> -		ret = -ENODEV;
> -		sb = get_super(dev);
> -		if (!sb)
> -			goto out;
> -	}
> -
> -	ret = -EINVAL;
> -	switch (cmds) {
> -		case Q_QUOTAON:
> -			ret = quota_on(sb, type, (char *) addr);
> -			goto out;
> -		case Q_QUOTAOFF:
> -			ret = quota_off(sb, type);
> -			goto out;
> -		case Q_GETQUOTA:
> -			ret = get_quota(sb, id, type, (struct mem_dqblk *) addr);
> -			goto out;
> -		case Q_SETQUOTA:
> -			flags |= SET_QUOTA;
> -			break;
> -		case Q_SETUSE:
> -			flags |= SET_USE;
> -			break;
> -		case Q_SETQLIM:
> -			flags |= SET_QLIMIT;
> -			break;
> -		case Q_SYNC:
> -			ret = sync_dquots(dev, type);
> -			goto out;
> -		case Q_GETSTATS:
> -			ret = get_stats(addr);
> -			goto out;
> -		case Q_GETINFO:
> -			ret = get_info(sb, type, (struct mem_dqinfo *) addr);
> -			goto out;
> -		case Q_SETFLAGS:
> -			ret = set_info(ISET_FLAGS, sb, type, (struct mem_dqinfo *)addr);
> -			goto out;
> -		case Q_SETGRACE:
> -			ret = set_info(ISET_GRACE, sb, type, (struct mem_dqinfo *)addr);
> -			goto out;
> -		case Q_SETINFO:
> -			ret = set_info(ISET_ALL, sb, type, (struct mem_dqinfo *)addr);
> - 			goto out;
> -		default:
> -			goto out;
> -	}
> -
> -	ret = -NODEV;
> -	if (sb && sb_has_quota_enabled(sb, type))
> -		ret = set_dqblk(sb, id, type, flags, (struct mem_dqblk *) addr);
> -out:
> -	if (sb)
> -		drop_super(sb);
> -	unlock_kernel();
> -	return ret;
> -}
> +struct quota_operations generic_quota_ops = {
> +	quotaon:	quota_on,
> +	quotaoff:	quota_off,
> +	quotasync:	quota_sync,
> +	getinfo:	get_info,
> +	setinfo:	set_info,
> +	getdqblk:	get_dqblk,
> +	setdqblk:	set_dqblk,
> +};
> diff -Naur 2.4.18-pre3-ac2/fs/noquot.c 2.4.18-pre3-ac2-quotactl/fs/noquot.c
> --- 2.4.18-pre3-ac2/fs/noquot.c	Sat May 13 04:21:20 2000
> +++ 2.4.18-pre3-ac2-quotactl/fs/noquot.c	Thu Jan  1 10:00:00 1970
> @@ -1,15 +0,0 @@
> -/* noquot.c: Quota stubs necessary for when quotas are not
> - *           compiled into the kernel.
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/types.h>
> -#include <linux/errno.h>
> -
> -int nr_dquots, nr_free_dquots;
> -int max_dquots;
> -
> -asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
> -{
> -	return(-ENOSYS);
> -}
> diff -Naur 2.4.18-pre3-ac2/fs/quota.c 2.4.18-pre3-ac2-quotactl/fs/quota.c
> --- 2.4.18-pre3-ac2/fs/quota.c	Thu Jan  1 10:00:00 1970
> +++ 2.4.18-pre3-ac2-quotactl/fs/quota.c	Wed Jan 23 15:08:49 2002
> @@ -0,0 +1,204 @@
> +/*
> + * Quota code necessary even when VFS quota support is not compiled
> + * into the kernel.  The interesting stuff is over in dquot.c, here
> + * we have symbols for initial quotactl(2) handling, the sysctl(2)
> + * variables, etc - things needed even when quota support disabled.
> + */
> +
> +#include <linux/fs.h>
> +#include <asm/current.h>
> +#include <asm/uaccess.h>
> +#include <linux/kernel.h>
> +#include <linux/smp_lock.h>
> +
> +int nr_dquots, nr_free_dquots;
> +
> +static struct super_block *
> +validate_quotactl(int cmd, int type, const char *special, qid_t id)
> +{
> +	int ret;
> +	kdev_t dev;
> +	mode_t mode;
> +	struct nameidata nd;
> +	struct super_block *sb;
> +
> +	ret = -ENOSYS;
> +	if (cmd == 0x0800 || cmd == 0x1100)	/* both were Q_GETSTATS */
> +		goto error;
> +
> +	/* version/compatibility stuff - needs to be early on in the piece */
> +	ret = -EINVAL;
> +	if (cmd == 0x0300 || cmd == 0x0400 || cmd == 0x0500 || cmd == 0x1000
> +	    || cmd < 0x100)
> +		goto error;
> +	if (type >= MAXQUOTAS)
> +		goto error;
> +
> +	ret = -EPERM;
> +	switch (cmd) {
> +		case Q_SYNC:
> +		case Q_GETINFO:
> +		case Q_XGETQSTAT:
> +			break;
> +
> +		case Q_GETQUOTA:
> +		case Q_XGETQUOTA:
> +			if (((type == USRQUOTA && current->euid != id) ||
> +			     (type == GRPQUOTA && !in_egroup_p(id))) &&
> +			    !capable(CAP_SYS_ADMIN))
> +				goto error;
> +
> +		default:
> +			if (!capable(CAP_SYS_ADMIN))
> +				goto error;
> +	}
> +
> +	ret = -ENODEV;
> +	if (!special)
> +		goto error;
> +	ret = user_path_walk(special, &nd);
> +	if (ret)
> +		goto error;
> +
> +	dev = nd.dentry->d_inode->i_rdev;
> +	mode = nd.dentry->d_inode->i_mode;
> +	path_release(&nd);
> +
> +	ret = -ENOTBLK;
> +	if (!S_ISBLK(mode))
> +		goto error;
> +
> +	ret = -ENODEV;
> +	sb = get_super(dev);
> +	if (!sb)
> +		goto error;
> +
> +	ret = -ENOSYS;
> +	if (!sb->s_qop) {
> +		drop_super(sb);
> +		goto error;
> +	}
> +
> +	return sb;
> +error:
> +	return ERR_PTR(ret);
> +}
> +
> +asmlinkage long
> +sys_quotactl(int cmd, const char *special, qid_t id, __kernel_caddr_t addr)
> +{
> +	int ret, cmds, type;
> +	struct super_block *sb;
> +	union {
> +		char *pathname;
> +		unsigned int flags;
> +		struct mem_dqblk mdq;
> +		struct mem_dqinfo info;
> +		struct fs_disk_quota fdq;
> +		struct fs_quota_stat fqs;
> +	} u;  /* qualifies valid uses of "addr" */
> +
> +	lock_kernel();
> +	cmds = cmd >> SUBCMDSHIFT;
> +	type = cmd & SUBCMDMASK;
> +
> +	sb = validate_quotactl(cmds, type, special, id);
> +	if (IS_ERR(sb)) {
> +		unlock_kernel();
> +		return PTR_ERR(sb);
> +	}
> +
> +	ret = -EINVAL;
> +	switch (cmds) {
> +		case Q_QUOTAON:
> +			u.pathname = (char *)addr;
> +			if (sb->s_qop->quotaon)
> +				ret = sb->s_qop->quotaon(sb, type, u.pathname);
> +			break;
> +
> +		case Q_QUOTAOFF:
> +			if (sb->s_qop->quotaoff)
> +				ret = sb->s_qop->quotaoff(sb, type);
> +			break;
> +
> +	    	case Q_SYNC:
> +			if (sb->s_qop->quotasync)
> +				ret = sb->s_qop->quotasync(sb, type);
> +			break;
> +
> +		case Q_GETINFO:
> +			if (sb->s_qop->getinfo)
> +				ret = sb->s_qop->getinfo(sb, type, &u.info);
> +			if (!ret && copy_to_user(addr, &u.info, sizeof(u.info)))
> +				ret = -EFAULT;
> +			break;
> +
> +		case Q_SETINFO:
> +		case Q_SETFLAGS:
> +		case Q_SETGRACE:
> +			if (!sb->s_qop->setinfo)
> +				break;
> +			ret = -EFAULT;
> +			if (copy_from_user(&u.info, addr, sizeof(u.info)))
> +				break;
> +			ret = sb->s_qop->setinfo(sb, type, &u.info, cmds);
> +			break;
> +
> +		case Q_GETQUOTA:
> +			if (sb->s_qop->getdqblk)
> +				ret = sb->s_qop->getdqblk(sb, type, id, &u.mdq);
> +			if (!ret && copy_to_user(addr, &u.mdq, sizeof(u.mdq)))
> +				ret = -EFAULT;
> +			break;
> +
> +		case Q_SETUSE:
> +		case Q_SETQLIM:
> +		case Q_SETQUOTA:
> +			if (!sb->s_qop->setdqblk)
> +				break;
> +			ret = -EFAULT;
> +			if (copy_from_user(&u.mdq, addr, sizeof(u.mdq)))
> +				break;
> +			ret = sb->s_qop->setdqblk(sb, type, id, &u.mdq, cmds);
> +			break;
> +
> +		case Q_XQUOTAON:
> +		case Q_XQUOTAOFF:
> +		case Q_XQUOTARM:
> +			if (!sb->s_qop->setxstate)
> +				break;
> +			ret = -EFAULT;
> +			if (copy_from_user(&u.flags, addr, sizeof(u.flags)))
> +				break;
> +			ret = sb->s_qop->setxstate(sb, u.flags, cmds);
> +			break;
> +
> +		case Q_XGETQSTAT:
> +			if (sb->s_qop->getxstate)
> +				ret = sb->s_qop->getxstate(sb, &u.fqs);
> +			if (!ret && copy_to_user(addr, &u.fqs, sizeof(u.fqs)))
> +				ret = -EFAULT;
> +			break;
> +
> +		case Q_XSETQLIM:
> +			if (!sb->s_qop->setxquota)
> +				break;
> +			ret = -EFAULT;
> +			if (copy_from_user(&u.fdq, addr, sizeof(u.fdq)))
> +				break;
> +			ret = sb->s_qop->setxquota(sb, type, id, &u.fdq);
> +			break;
> +
> +		case Q_XGETQUOTA:
> +			if (sb->s_qop->getxquota)
> +				ret = sb->s_qop->getxquota(sb, type, id, &u.fdq);
> +			if (!ret && copy_to_user(addr, &u.fdq, sizeof(u.fdq)))
> +				ret = -EFAULT;
> +			break;
> +
> +		default:
> +	}
> +	drop_super(sb);
> +	unlock_kernel();
> +	return ret;
> +}
> diff -Naur 2.4.18-pre3-ac2/fs/super.c 2.4.18-pre3-ac2-quotactl/fs/super.c
> --- 2.4.18-pre3-ac2/fs/super.c	Sat Dec 22 04:42:03 2001
> +++ 2.4.18-pre3-ac2-quotactl/fs/super.c	Wed Jan 23 12:26:41 2002
> @@ -437,6 +437,7 @@
>  		sema_init(&s->s_dquot.dqio_sem, 1);
>  		sema_init(&s->s_dquot.dqoff_sem, 1);
>  		s->s_maxbytes = MAX_NON_LFS;
> +		s->s_qop = sb_generic_quota_ops;
>  	}
>  	return s;
>  }
> diff -Naur 2.4.18-pre3-ac2/include/linux/fs.h 2.4.18-pre3-ac2-quotactl/include/linux/fs.h
> --- 2.4.18-pre3-ac2/include/linux/fs.h	Wed Jan 23 12:24:44 2002
> +++ 2.4.18-pre3-ac2-quotactl/include/linux/fs.h	Wed Jan 23 14:50:06 2002
> @@ -365,6 +365,7 @@
>  /*
>   * Includes for diskquotas and mount structures.
>   */
> +#include <linux/xqm.h>
>  #include <linux/quota.h>
>  #include <linux/mount.h>
>  
> @@ -691,6 +692,20 @@
>  	struct mem_dqinfo info[MAXQUOTAS];	/* Information for each quota type */
>  };
>  
> +struct quota_operations {
> +	int (*quotaon)(struct super_block *, short, char *);
> +	int (*quotaoff)(struct super_block *, short);
> +	int (*quotasync)(struct super_block *, short);
> +	int (*getinfo)(struct super_block *, short, struct mem_dqinfo *);
> +	int (*setinfo)(struct super_block *, short, struct mem_dqinfo *, int);
> +	int (*getdqblk)(struct super_block *, short, qid_t, struct mem_dqblk *);
> +	int (*setdqblk)(struct super_block *, short, qid_t, struct mem_dqblk *, int);
> +	int (*getxstate)(struct super_block *, struct fs_quota_stat *);
> +	int (*setxstate)(struct super_block *, unsigned int, int);
> +	int (*getxquota)(struct super_block *, short, qid_t, struct fs_disk_quota *);
> +	int (*setxquota)(struct super_block *, short, qid_t, struct fs_disk_quota *);
> +};
> +
>  /*
>   *	Umount options
>   */
> @@ -752,7 +767,8 @@
>  
>  	struct block_device	*s_bdev;
>  	struct list_head	s_instances;
> - 	struct quota_info s_dquot;	/* Diskquota specific options */
> + 	struct quota_info	s_dquot;	/* Diskquota specific options */
> +	struct quota_operations	*s_qop;
>  
>  	union {
>  		struct minix_sb_info	minix_sb;
> diff -Naur 2.4.18-pre3-ac2/include/linux/quota.h 2.4.18-pre3-ac2-quotactl/include/linux/quota.h
> --- 2.4.18-pre3-ac2/include/linux/quota.h	Wed Jan 23 12:24:44 2002
> +++ 2.4.18-pre3-ac2-quotactl/include/linux/quota.h	Wed Jan 23 14:43:51 2002
> @@ -107,7 +107,7 @@
>  #define Q_SETQUOTA 0x0E00	/* set limits and usage */
>  #define Q_SETUSE   0x0F00	/* set usage */
>  /* 0x1000 used by old RSQUASH */
> -#define Q_GETSTATS 0x1100	/* get collected stats */
> +/* 0x1100 used by GETSTATS v2, since replaced by procfs entry */
>  
>  /*
>   * The following structure defines the format of the disk quota file
> @@ -255,13 +255,6 @@
>  #define dq_btime dq_dqb.dqb_btime
>  
>  /*
> - * Flags used for set_dqblk.
> - */
> -#define SET_QUOTA         0x01
> -#define SET_USE           0x02
> -#define SET_QLIMIT        0x04
> -
> -/*
>   * Flags used for set_info
>   */
>  #define ISET_GRACE 0x01
> diff -Naur 2.4.18-pre3-ac2/include/linux/quotaops.h 2.4.18-pre3-ac2-quotactl/include/linux/quotaops.h
> --- 2.4.18-pre3-ac2/include/linux/quotaops.h	Wed Jan 23 12:24:44 2002
> +++ 2.4.18-pre3-ac2-quotactl/include/linux/quotaops.h	Wed Jan 23 15:03:56 2002
> @@ -17,6 +17,9 @@
>  
>  #include <linux/fs.h>
>  
> +extern struct quota_operations generic_quota_ops;
> +#define sb_generic_quota_ops (&generic_quota_ops)
> +
>  /*
>   * declaration of quota_function calls in kernel.
>   */
> @@ -167,6 +170,7 @@
>  /*
>   * NO-OP when quota not configured.
>   */
> +#define sb_generic_quota_ops			(NULL)
>  #define DQUOT_INIT(inode)			do { } while(0)
>  #define DQUOT_DROP(inode)			do { } while(0)
>  #define DQUOT_ALLOC_INODE(inode)		(0)
> diff -Naur 2.4.18-pre3-ac2/include/linux/sysctl.h 2.4.18-pre3-ac2-quotactl/include/linux/sysctl.h
> --- 2.4.18-pre3-ac2/include/linux/sysctl.h	Wed Jan 23 12:24:44 2002
> +++ 2.4.18-pre3-ac2-quotactl/include/linux/sysctl.h	Wed Jan 23 14:43:51 2002
> @@ -533,7 +533,7 @@
>  	FS_STATINODE=2,
>  	FS_MAXINODE=3,	/* int:maximum number of inodes that can be allocated */
>  	FS_NRDQUOT=4,	/* int:current number of allocated dquots */
> -	FS_MAXDQUOT=5,	/* int:maximum number of dquots that can be allocated */
> +	/* was FS_MAXDQUOT */
>  	FS_NRFILE=6,	/* int:current number of allocated filedescriptors */
>  	FS_MAXFILE=7,	/* int:maximum number of filedescriptors that can be allocated */
>  	FS_DENTRY=8,
> diff -Naur 2.4.18-pre3-ac2/include/linux/xqm.h 2.4.18-pre3-ac2-quotactl/include/linux/xqm.h
> --- 2.4.18-pre3-ac2/include/linux/xqm.h	Thu Jan  1 10:00:00 1970
> +++ 2.4.18-pre3-ac2-quotactl/include/linux/xqm.h	Wed Jan 23 14:43:51 2002
> @@ -0,0 +1,159 @@
> +/*
> + * Copyright (c) 1995-2001 Silicon Graphics, Inc.  All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2.1 of the GNU Lesser General Public License
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> + *
> + * Further, this software is distributed without any warranty that it is
> + * free of the rightful claim of any third person regarding infringement
> + * or the like.  Any license provided herein, whether implied or
> + * otherwise, applies only to this software file.  Patent licenses, if
> + * any, provided herein do not apply to combinations of this program with
> + * other software, or any other product whatsoever.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this program; if not, write the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
> + * USA.
> + *
> + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
> + * Mountain View, CA  94043, or:
> + *
> + * http://www.sgi.com
> + *
> + * For further information regarding this notice, see:
> + *
> + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
> + */
> +#ifndef _LINUX_XQM_H
> +#define _LINUX_XQM_H
> +
> +#include <linux/types.h>
> +
> +/*
> + * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM).
> + */
> +
> +#define XQM_CMD(x)	(('X'<<8)+(x))	/* note: forms first QCMD argument */
> +#define Q_XQUOTAON	XQM_CMD(0x1)	/* enable accounting/enforcement */
> +#define Q_XQUOTAOFF	XQM_CMD(0x2)	/* disable accounting/enforcement */
> +#define Q_XGETQUOTA	XQM_CMD(0x3)	/* get disk limits and usage */
> +#define Q_XSETQLIM	XQM_CMD(0x4)	/* set disk limits */
> +#define Q_XGETQSTAT	XQM_CMD(0x5)	/* get quota subsystem status */
> +#define Q_XQUOTARM	XQM_CMD(0x6)	/* free disk space used by dquots */
> +
> +/*
> + * fs_disk_quota structure:
> + *
> + * This contains the current quota information regarding a user/proj/group.
> + * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of
> + * 512 bytes.
> + */
> +#define FS_DQUOT_VERSION	1	/* fs_disk_quota.d_version */
> +typedef struct fs_disk_quota {
> +	__s8		d_version;	/* version of this structure */
> +	__s8		d_flags;	/* XFS_{USER,PROJ,GROUP}_QUOTA */
> +	__u16		d_fieldmask;	/* field specifier */
> +	__u32		d_id;		/* user, project, or group ID */
> +	__u64		d_blk_hardlimit;/* absolute limit on disk blks */
> +	__u64		d_blk_softlimit;/* preferred limit on disk blks */
> +	__u64		d_ino_hardlimit;/* maximum # allocated inodes */
> +	__u64		d_ino_softlimit;/* preferred inode limit */
> +	__u64		d_bcount;	/* # disk blocks owned by the user */
> +	__u64		d_icount;	/* # inodes owned by the user */
> +	__s32		d_itimer;	/* zero if within inode limits */
> +					/* if not, we refuse service */
> +	__s32		d_btimer;	/* similar to above; for disk blocks */
> +	__u16	  	d_iwarns;       /* # warnings issued wrt num inodes */
> +	__u16	  	d_bwarns;       /* # warnings issued wrt disk blocks */
> +	__s32		d_padding2;	/* padding2 - for future use */
> +	__u64		d_rtb_hardlimit;/* absolute limit on realtime blks */
> +	__u64		d_rtb_softlimit;/* preferred limit on RT disk blks */
> +	__u64		d_rtbcount;	/* # realtime blocks owned */
> +	__s32		d_rtbtimer;	/* similar to above; for RT disk blks */
> +	__u16	  	d_rtbwarns;     /* # warnings issued wrt RT disk blks */
> +	__s16		d_padding3;	/* padding3 - for future use */	
> +	char		d_padding4[8];	/* yet more padding */
> +} fs_disk_quota_t;
> +
> +/*
> + * These fields are sent to Q_XSETQLIM to specify fields that need to change.
> + */
> +#define FS_DQ_ISOFT	(1<<0)
> +#define FS_DQ_IHARD	(1<<1)
> +#define FS_DQ_BSOFT	(1<<2)
> +#define FS_DQ_BHARD 	(1<<3)
> +#define FS_DQ_RTBSOFT	(1<<4)
> +#define FS_DQ_RTBHARD	(1<<5)
> +#define FS_DQ_LIMIT_MASK	(FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \
> +				 FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD)
> +/*
> + * These timers can only be set in super user's dquot. For others, timers are
> + * automatically started and stopped. Superusers timer values set the limits
> + * for the rest.  In case these values are zero, the DQ_{F,B}TIMELIMIT values
> + * defined below are used. 
> + * These values also apply only to the d_fieldmask field for Q_XSETQLIM.
> + */
> +#define FS_DQ_BTIMER	(1<<6)
> +#define FS_DQ_ITIMER	(1<<7)
> +#define FS_DQ_RTBTIMER 	(1<<8)
> +#define FS_DQ_TIMER_MASK	(FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER)
> +
> +/*
> + * The following constants define the default amount of time given a user
> + * before the soft limits are treated as hard limits (usually resulting
> + * in an allocation failure).  These may be modified by the quotactl(2)
> + * system call with the Q_XSETQLIM command.
> + */
> +#define	DQ_FTIMELIMIT	(7 * 24*60*60)		/* 1 week */
> +#define	DQ_BTIMELIMIT	(7 * 24*60*60)		/* 1 week */
> +
> +/*
> + * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
> + */
> +#define XFS_QUOTA_UDQ_ACCT	(1<<0)  /* user quota accounting */
> +#define XFS_QUOTA_UDQ_ENFD	(1<<1)  /* user quota limits enforcement */
> +#define XFS_QUOTA_GDQ_ACCT	(1<<2)  /* group quota accounting */
> +#define XFS_QUOTA_GDQ_ENFD	(1<<3)  /* group quota limits enforcement */
> +
> +#define XFS_USER_QUOTA		(1<<0)	/* user quota type */
> +#define XFS_PROJ_QUOTA		(1<<1)	/* (IRIX) project quota type */
> +#define XFS_GROUP_QUOTA		(1<<2)	/* group quota type */
> +
> +/*
> + * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system.
> + * Provides a centralized way to get meta infomation about the quota subsystem.
> + * eg. space taken up for user and group quotas, number of dquots currently
> + * incore.
> + */
> +#define FS_QSTAT_VERSION	1	/* fs_quota_stat.qs_version */
> +
> +/*
> + * Some basic infomation about 'quota files'.
> + */
> +typedef struct fs_qfilestat {
> +	__u64		qfs_ino;	/* inode number */
> +	__u64		qfs_nblks;	/* number of BBs 512-byte-blks */
> +	__u32		qfs_nextents;	/* number of extents */
> +} fs_qfilestat_t;
> +
> +typedef struct fs_quota_stat {
> +	__s8		qs_version;	/* version number for future changes */
> +	__u16		qs_flags;	/* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
> +	__s8		qs_pad;		/* unused */
> +	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
> +	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
> +	__u32		qs_incoredqs;	/* number of dquots incore */
> +	__s32		qs_btimelimit;  /* limit for blks timer */	
> +	__s32		qs_itimelimit;  /* limit for inodes timer */	
> +	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
> +	__u16		qs_bwarnlimit;	/* limit for num warnings */
> +	__u16		qs_iwarnlimit;	/* limit for num warnings */
> +} fs_quota_stat_t;
> +
> +#endif	/* _LINUX_XQM_H */



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Quota & XFS patch
  2002-02-27 16:42 ` Alexander Viro
@ 2002-02-27 21:39   ` Jan Kara
  0 siblings, 0 replies; 4+ messages in thread
From: Jan Kara @ 2002-02-27 21:39 UTC (permalink / raw)
  To: Alexander Viro; +Cc: Alan Cox, Nathan Scott, linux-kernel

> On Wed, 27 Feb 2002, Jan Kara wrote:
> 
> >   Hello,
> > 
> >   I'm sending you Nathan's patch which implements things
> > in quotactl interface needed for XFS. If you can remember
> > the patch was already floating around some time
> > ago and was generally accepted... Please apply (it will
> > at least simplify patching of kernels for XFS).
> 
> Why are you leaving some copy_from_user() in methods?  Either the structures
> you are passing are fs-independent and everybody would be better off with
> having them copied in one place or they are not, and then API is completely
> broken.
  Umm... I'm not sure I understand your objections - as I'm looking into the patch
all the copy_from_user() were moved from functions into sys_quotactl(). The
only thing you might not like is that XFS has extra structures and calls...
I don't like this too much either but XFS has different quota model so
creating common interface (structures) is a problem.

						Thanks for comments
									Honza

PS: Alan is not going to accept the patch anyway because he doesn't want further
  interface differences between his and Linus's tree. But anyway discussion on this
  topic is useful because I have similar patch for 2.5...

--
Jan Kara <jack@suse.cz>
SuSE CR Labs

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2002-02-27 21:41 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-02-27 16:09 Quota & XFS patch Jan Kara
2002-02-27 16:42 ` Alexander Viro
2002-02-27 21:39   ` Jan Kara
2002-02-27 19:16 ` Shawn Starr

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox