LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* Quotactl change
@ 2001-10-06 13:07 Jan Kara
  2001-10-06 18:25 ` Alexander Viro
  0 siblings, 1 reply; 7+ messages in thread
From: Jan Kara @ 2001-10-06 13:07 UTC (permalink / raw)
  To: Alan Cox; +Cc: Nathan Scott, linux-kernel

  Hello,

  I'm sending you a change for quotactl interface which Nathan Scott proposed
for XFS. Actually it's his patch with just a few changes from me.
  It allows quotactl() to be overidden by a filesystem and so XFS can do it's
tricks with quota without patching dquot.c. Sideeffect of this change is a
cleanup in quotactl() interface :).
  Also statistics about quotas are now exported to /proc which is IMO more
flexible and nicer than GETSTATS call.
  I also commented out MAXDQUOTS sysctl because it has no sense anymore.
BTW: IMHO the same can be done with MAXINODES.

								Honza

------------------------------------<cut>--------------------------------
diff -ruN -X /home/jack/.kerndiffexclude linux-2.4.10-ac3-fix/fs/Makefile linux-2.4.10-ac3-fix+quotactl/fs/Makefile
--- linux-2.4.10-ac3-fix/fs/Makefile	Wed Oct  3 23:38:37 2001
+++ linux-2.4.10-ac3-fix+quotactl/fs/Makefile	Sat Oct  6 10:46:35 2001
@@ -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 jbd-kernel.o namespace.o
+		filesystems.o jbd-kernel.o namespace.o quota.o
 
 ifeq ($(CONFIG_QUOTA),y)
 obj-y += dquot.o
-else
-obj-y += noquot.o
 endif
 
 subdir-$(CONFIG_PROC_FS)	+= proc
diff -ruN -X /home/jack/.kerndiffexclude linux-2.4.10-ac3-fix/fs/dquot.c linux-2.4.10-ac3-fix+quotactl/fs/dquot.c
--- linux-2.4.10-ac3-fix/fs/dquot.c	Thu Oct  4 12:25:37 2001
+++ linux-2.4.10-ac3-fix+quotactl/fs/dquot.c	Sat Oct  6 11:57:06 2001
@@ -65,6 +65,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 +74,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;
@@ -1480,11 +1479,13 @@
 static int set_dqblk(struct super_block *sb, qid_t id, short type, int flags, struct mem_dqblk *dqblk)
 {
 	struct dquot *dquot;
-	int error = -EFAULT;
 	struct mem_dqblk dq_dqblk;
 
+	if (!sb || !sb_has_quota_enabled(sb, type))
+		return -ESRCH;
+
 	if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct mem_dqblk)))
-		return error;
+		return -EFAULT;
 
 	if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) {
 		/* We can't block while changing quota structure... */
@@ -1550,20 +1551,38 @@
 	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)
 {
@@ -1886,6 +1905,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);
@@ -2043,115 +2063,59 @@
 	return error; 
 }
 
-/*
- * 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.
- */
-asmlinkage long sys_quotactl(int cmd, const char *special, qid_t id, __kernel_caddr_t addr)
+static int generic_quotactl(struct super_block *sb, int cmd, int type, qid_t id, void *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 ((uint) type >= MAXQUOTAS || cmds > 0x1100 || cmds < 0x100 || cmds == 0x0300 ||
-	    cmds == 0x0400 || cmds == 0x0500 || cmds == 0x1000)
-		goto out;
+	if ((uint) type >= MAXQUOTAS || cmd > 0x1100 || cmd < 0x100 ||
+	    cmd == 0x0300 || cmd == 0x0400 || cmd == 0x0500 || cmd == 0x1000)
+		return ret;
 
 	ret = -EPERM;
-	switch (cmds) {
+	switch (cmd) {
 		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;
+				return ret;
 			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;
+				return ret;
 	}
 
 	ret = -EINVAL;
-	switch (cmds) {
+	switch (cmd) {
 		case Q_QUOTAON:
-			ret = quota_on(sb, type, (char *) addr);
-			goto out;
+			return quota_on(sb, type, (char *) addr);
 		case Q_QUOTAOFF:
-			ret = quota_off(sb, type);
-			goto out;
+			return quota_off(sb, type);
 		case Q_GETQUOTA:
-			ret = get_quota(sb, id, type, (struct mem_dqblk *) addr);
-			goto out;
+			return get_quota(sb, id, type, (struct mem_dqblk *) addr);
 		case Q_SETQUOTA:
-			flags |= SET_QUOTA;
-			break;
+			return set_dqblk(sb, id, type, SET_QUOTA, (struct mem_dqblk *) addr);
 		case Q_SETUSE:
-			flags |= SET_USE;
-			break;
+			return set_dqblk(sb, id, type, SET_USE, (struct mem_dqblk *) addr);
 		case Q_SETQLIM:
-			flags |= SET_QLIMIT;
-			break;
+			return set_dqblk(sb, id, type, SET_QLIMIT, (struct mem_dqblk *) addr);
 		case Q_SYNC:
-			ret = sync_dquots(dev, type);
-			goto out;
-		case Q_GETSTATS:
-			ret = get_stats(addr);
-			goto out;
+			return sync_dquots(sb->s_dev, type);
 		case Q_GETINFO:
-			ret = get_info(sb, type, (struct mem_dqinfo *) addr);
-			goto out;
+			return get_info(sb, type, (struct mem_dqinfo *) addr);
 		case Q_SETFLAGS:
-			ret = set_info(ISET_FLAGS, sb, type, (struct mem_dqinfo *)addr);
-			goto out;
+			return set_info(ISET_FLAGS, sb, type, (struct mem_dqinfo *)addr);
 		case Q_SETGRACE:
-			ret = set_info(ISET_GRACE, sb, type, (struct mem_dqinfo *)addr);
-			goto out;
+			return set_info(ISET_GRACE, sb, type, (struct mem_dqinfo *)addr);
 		case Q_SETINFO:
-			ret = set_info(ISET_ALL, sb, type, (struct mem_dqinfo *)addr);
- 			goto out;
+			return set_info(ISET_ALL, sb, type, (struct mem_dqinfo *)addr);
 		default:
-			goto out;
+			return ret;
 	}
-
-	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 = {
+	quotactl:	generic_quotactl
+};
diff -ruN -X /home/jack/.kerndiffexclude linux-2.4.10-ac3-fix/fs/noquot.c linux-2.4.10-ac3-fix+quotactl/fs/noquot.c
--- linux-2.4.10-ac3-fix/fs/noquot.c	Wed Oct  3 23:38:40 2001
+++ linux-2.4.10-ac3-fix+quotactl/fs/noquot.c	Thu Jan  1 01:00:00 1970
@@ -1,20 +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);
-}
-
-void shrink_dqcache_memory(int priority, unsigned int gfp_mask)
-{
-	;
-}
diff -ruN -X /home/jack/.kerndiffexclude linux-2.4.10-ac3-fix/fs/quota.c linux-2.4.10-ac3-fix+quotactl/fs/quota.c
--- linux-2.4.10-ac3-fix/fs/quota.c	Thu Jan  1 01:00:00 1970
+++ linux-2.4.10-ac3-fix+quotactl/fs/quota.c	Sat Oct  6 11:57:27 2001
@@ -0,0 +1,68 @@
+/*
+ * Quota code necessary even when VFS quota support is not compiled
+ * into the kernel.  Allows filesystems to implement their own form
+ * of quota if they wish.  The interesting stuff is over in dquot.c,
+ * living here are symbols for initial quotactl(2) handling, sysctl
+ * variables, etc - things needed even when quota support disabled.
+ */
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+
+int nr_dquots, nr_free_dquots;
+
+#ifndef CONFIG_QUOTA
+void shrink_dqcache_memory(int priority, unsigned int mask)
+{
+	return;
+}
+#endif
+
+asmlinkage long sys_quotactl(int cmd, const char *special, qid_t id, __kernel_caddr_t addr)
+{
+	int ret, cmds, type;
+	kdev_t dev;
+	mode_t mode;
+	struct nameidata nd;
+	struct super_block *sb = NULL;
+
+	lock_kernel();
+	cmds = cmd >> SUBCMDSHIFT;
+	type = cmd & SUBCMDMASK;
+
+	ret = -ENOSYS;
+	if (cmds == 0x0800 || cmds == 0x1100)	/* both were Q_GETSTATS */
+		goto out;
+
+	ret = -ENODEV;
+	if (!special)
+		goto out;
+	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 = -ENOSYS;
+	if (!sb->s_qop || !sb->s_qop->quotactl)
+		goto out;
+
+	ret = sb->s_qop->quotactl(sb, cmds, type, id, addr);
+
+out:
+	if (sb)
+		drop_super(sb);
+	unlock_kernel();
+	return ret;
+}
diff -ruN -X /home/jack/.kerndiffexclude linux-2.4.10-ac3-fix/fs/super.c linux-2.4.10-ac3-fix+quotactl/fs/super.c
--- linux-2.4.10-ac3-fix/fs/super.c	Wed Oct  3 23:38:42 2001
+++ linux-2.4.10-ac3-fix+quotactl/fs/super.c	Sat Oct  6 10:46:35 2001
@@ -466,6 +466,7 @@
 	s->s_bdev = bdev;
 	s->s_flags = flags;
 	s->s_type = type;
+	s->s_qop = sb_generic_quota_ops;
 	spin_lock(&sb_lock);
 	list_add (&s->s_list, super_blocks.prev);
 	list_add (&s->s_instances, &type->fs_supers);
@@ -486,6 +487,7 @@
 	s->s_dev = 0;
 	s->s_bdev = 0;
 	s->s_type = NULL;
+	s->s_qop = NULL;
 	unlock_super(s);
 	spin_lock(&sb_lock);
 	list_del(&s->s_list);
@@ -617,6 +619,7 @@
 	s->s_bdev = bdev;
 	s->s_flags = flags;
 	s->s_type = fs_type;
+	s->s_qop = sb_generic_quota_ops;
 	list_add (&s->s_list, super_blocks.prev);
 	list_add (&s->s_instances, &fs_type->fs_supers);
 	s->s_count += S_BIAS;
@@ -636,6 +639,7 @@
 	s->s_dev = 0;
 	s->s_bdev = 0;
 	s->s_type = NULL;
+	s->s_qop = NULL;
 	unlock_super(s);
 	spin_lock(&sb_lock);
 	list_del(&s->s_list);
@@ -700,6 +704,7 @@
 		s->s_dev = dev;
 		s->s_flags = flags;
 		s->s_type = fs_type;
+		s->s_qop = sb_generic_quota_ops;
 		list_add (&s->s_list, super_blocks.prev);
 		list_add (&s->s_instances, &fs_type->fs_supers);
 		s->s_count += S_BIAS;
@@ -715,6 +720,7 @@
 		s->s_dev = 0;
 		s->s_bdev = 0;
 		s->s_type = NULL;
+		s->s_qop = NULL;
 		unlock_super(s);
 		spin_lock(&sb_lock);
 		list_del(&s->s_list);
@@ -770,6 +776,7 @@
 	sb->s_bdev = NULL;
 	put_filesystem(fs);
 	sb->s_type = NULL;
+	sb->s_qop = NULL;
 	unlock_super(sb);
 	unlock_kernel();
 	if (bdev)
diff -ruN -X /home/jack/.kerndiffexclude linux-2.4.10-ac3-fix/include/linux/fs.h linux-2.4.10-ac3-fix+quotactl/include/linux/fs.h
--- linux-2.4.10-ac3-fix/include/linux/fs.h	Sat Oct  6 11:03:30 2001
+++ linux-2.4.10-ac3-fix+quotactl/include/linux/fs.h	Sat Oct  6 12:03:54 2001
@@ -656,6 +656,10 @@
 	struct mem_dqinfo info[MAXQUOTAS];	/* Information for each quota type */
 };
 
+struct quota_operations {
+	int (*quotactl)(struct super_block *, int, int, qid_t, void *);
+};
+
 /*
  *	Umount options
  */
@@ -717,6 +721,7 @@
 	struct block_device	*s_bdev;
 	struct list_head	s_instances;
 	struct quota_info	s_dquot;	/* Diskquota specific options */
+	struct quota_operations	*s_qop;
 
 	union {
 		struct minix_sb_info	minix_sb;
diff -ruN -X /home/jack/.kerndiffexclude linux-2.4.10-ac3-fix/include/linux/quota.h linux-2.4.10-ac3-fix+quotactl/include/linux/quota.h
--- linux-2.4.10-ac3-fix/include/linux/quota.h	Wed Oct  3 23:38:47 2001
+++ linux-2.4.10-ac3-fix+quotactl/include/linux/quota.h	Sat Oct  6 11:56:35 2001
@@ -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
diff -ruN -X /home/jack/.kerndiffexclude linux-2.4.10-ac3-fix/include/linux/quotaops.h linux-2.4.10-ac3-fix+quotactl/include/linux/quotaops.h
--- linux-2.4.10-ac3-fix/include/linux/quotaops.h	Sat Oct  6 11:09:14 2001
+++ linux-2.4.10-ac3-fix+quotactl/include/linux/quotaops.h	Sat Oct  6 12:17:15 2001
@@ -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.
  */
@@ -166,6 +169,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 -ruN -X /home/jack/.kerndiffexclude linux-2.4.10-ac3-fix/include/linux/sysctl.h linux-2.4.10-ac3-fix+quotactl/include/linux/sysctl.h
--- linux-2.4.10-ac3-fix/include/linux/sysctl.h	Sat Oct  6 11:04:28 2001
+++ linux-2.4.10-ac3-fix+quotactl/include/linux/sysctl.h	Sat Oct  6 12:04:13 2001
@@ -535,7 +535,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,

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

* Re: Quotactl change
  2001-10-06 13:07 Quotactl change Jan Kara
@ 2001-10-06 18:25 ` Alexander Viro
  2001-10-08  2:19   ` Nathan Scott
  2001-10-08 10:34   ` Nathan Scott
  0 siblings, 2 replies; 7+ messages in thread
From: Alexander Viro @ 2001-10-06 18:25 UTC (permalink / raw)
  To: Jan Kara; +Cc: Alan Cox, Nathan Scott, linux-kernel



On Sat, 6 Oct 2001, Jan Kara wrote:

>   Hello,
> 
>   I'm sending you a change for quotactl interface which Nathan Scott proposed
> for XFS. Actually it's his patch with just a few changes from me.
>   It allows quotactl() to be overidden by a filesystem and so XFS can do it's
> tricks with quota without patching dquot.c. Sideeffect of this change is a
> cleanup in quotactl() interface :).

[snip]

	Umm...  So you've just given to each fs driver a syscall with
completely unspecified arguments?  I _really_ doubt that it's a good
idea, especially since each instance will have to copy structures
to/from userland.

	Please, put switch by the first argument and copy_{to,from}_user()
into the syscall itself.  Yes, it means more methods, but it helps to avoid
large PITA couple of years down the road.


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

* Re: Quotactl change
  2001-10-06 18:25 ` Alexander Viro
@ 2001-10-08  2:19   ` Nathan Scott
  2001-10-08 10:34   ` Nathan Scott
  1 sibling, 0 replies; 7+ messages in thread
From: Nathan Scott @ 2001-10-08  2:19 UTC (permalink / raw)
  To: Alexander Viro, Jan Kara, Alan Cox; +Cc: linux-kernel, linux-xfs

hi Al,

On Sat, Oct 06, 2001 at 02:25:06PM -0400, Alexander Viro wrote:
> On Sat, Oct 06, 2001 at 03:07:32PM +0200, Jan Kara wrote:
> >   I'm sending you a change for quotactl interface which Nathan
> > Scott proposed for XFS. Actually it's his patch with just a few
> > changes from me.
> >   It allows quotactl() to be overidden by a filesystem and so XFS
> > can do it's tricks with quota without patching dquot.c. Sideeffect
> > of this change is a cleanup in quotactl() interface :).
> 
> [snip]
> 
> 	Umm...  So you've just given to each fs driver a syscall with
> completely unspecified arguments?  I _really_ doubt that it's a good
> idea, especially since each instance will have to copy structures
> to/from userland.
> 
> 	Please, put switch by the first argument and copy_{to,from}_user()
> into the syscall itself.  Yes, it means more methods, but it helps to avoid
> large PITA couple of years down the road.
> 

OK, if that's for the best, I'll rework it.  I thought it would
be cleaner to do it that other way, because it meant not having
any knowledge of the filesystem-specific quota data structures
and operations up at this higher (vfs) level.  Since ioctl is
available as a generic copy in/out facility already, I'm not
sure why any filesystem would abuse quotactl in this way, but
perhaps that's just human nature. ;-)

The only other reason that I was thinking of - I expect that 
Veritas' VxFS will also wish to provide its own quota subsystem,
as they seem to do for other operating systems.  Since (and I may
be wrong here) the intention there is to make VxFS a commercial
filesystem for Linux, it would also help those folk out if the
point of doing the user data copying was within the filesystem.
So, I was trying to do the right thing by everyone in making it
generic - your suggestion will work just fine for our needs in
XFS though.

Thanks for the feedback - new patch later.

cheers.

-- 
Nathan

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

* Re: Quotactl change
  2001-10-06 18:25 ` Alexander Viro
  2001-10-08  2:19   ` Nathan Scott
@ 2001-10-08 10:34   ` Nathan Scott
  2001-10-09  7:03     ` Alexander Viro
  2001-10-09  7:34     ` Jan Kara
  1 sibling, 2 replies; 7+ messages in thread
From: Nathan Scott @ 2001-10-08 10:34 UTC (permalink / raw)
  To: Alexander Viro; +Cc: Jan Kara, Alan Cox, linux-kernel, linux-xfs

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

hi all,

Al - is the attached patch more along the lines of what you
were after?

Jan - I think this is actually alot closer to what you were
talking about when we last discussed this.  Can you see any
problems from a VFS quota point of view here?  I had to make
small interface changes to a couple of the dquot.c routines
to make this simpler/more uniform in places - could you have
cross-check those for me?

many thanks.


On Sat, Oct 06, 2001 at 02:25:06PM -0400, Alexander Viro wrote:
> 
> 
> On Sat, 6 Oct 2001, Jan Kara wrote:
> 
> >   Hello,
> > 
> >   I'm sending you a change for quotactl interface which Nathan Scott proposed
> > for XFS. Actually it's his patch with just a few changes from me.
> >   It allows quotactl() to be overidden by a filesystem and so XFS can do it's
> > tricks with quota without patching dquot.c. Sideeffect of this change is a
> > cleanup in quotactl() interface :).
> 
> [snip]
> 
> 	Umm...  So you've just given to each fs driver a syscall with
> completely unspecified arguments?  I _really_ doubt that it's a good
> idea, especially since each instance will have to copy structures
> to/from userland.
> 
> 	Please, put switch by the first argument and copy_{to,from}_user()
> into the syscall itself.  Yes, it means more methods, but it helps to avoid
> large PITA couple of years down the road.
> 

-- 
Nathan

[-- Attachment #2: quotactl.patch2 --]
[-- Type: text/plain, Size: 28093 bytes --]

diff -Naur linux-2410ac8/fs/Makefile linux-2410ac8-quota/fs/Makefile
--- linux-2410ac8/fs/Makefile	Mon Oct  8 13:26:59 2001
+++ linux-2410ac8-quota/fs/Makefile	Mon Oct  8 19:45:36 2001
@@ -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 jbd-kernel.o namespace.o
+		filesystems.o jbd-kernel.o namespace.o quota.o
 
 ifeq ($(CONFIG_QUOTA),y)
 obj-y += dquot.o
-else
-obj-y += noquot.o
 endif
 
 subdir-$(CONFIG_PROC_FS)	+= proc
diff -Naur linux-2410ac8/fs/dquot.c linux-2410ac8-quota/fs/dquot.c
--- linux-2410ac8/fs/dquot.c	Mon Oct  8 13:26:59 2001
+++ linux-2410ac8-quota/fs/dquot.c	Mon Oct  8 19:53:03 2001
@@ -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;
@@ -988,10 +990,11 @@
 	}
 }
 
-int sync_dquots(kdev_t dev, short type)
+int sync_dquots(struct super_block *sb, short type)
 {
 	struct list_head *head;
 	struct dquot *dquot;
+	kdev_t dev = sb->s_dev;
 
 restart:
 	for (head = inuse_list.next; head != &inuse_list; head = head->next) {
@@ -1477,25 +1480,21 @@
  * 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)) {
+		if (op == Q_SETQUOTA || op == Q_SETQLIM) {
 			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 ((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)
@@ -1529,77 +1528,85 @@
 	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);
 			break;
-		case ISET_GRACE:
+		case Q_SETGRACE:
 			dqopt->info[type].dqi_bgrace = info.dqi_bgrace;
 			dqopt->info[type].dqi_igrace = info.dqi_igrace;
 			break;
-		case ISET_ALL:
+		case Q_SETINFO:
 			info.dqi_flags &= ~DQF_MASK;
 			memcpy(dqopt->info + type, &info, sizeof(struct mem_dqinfo));
 			break;
@@ -1886,6 +1893,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);
@@ -1939,9 +1947,6 @@
 	short cnt;
 	struct quota_info *dqopt = sb_dqopt(sb);
 
-	if (!sb)
-		goto out;
-
 	/* We need to serialize quota_off() for device */
 	down(&dqopt->dqoff_sem);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1963,7 +1968,6 @@
 		fput(filp);
 	}	
 	up(&dqopt->dqoff_sem);
-out:
 	return 0;
 }
 
@@ -2044,114 +2048,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 ((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,
+	sync:		sync_dquots,
+	getinfo:	get_info,
+	setinfo:	set_info,
+	getdqblk:	get_dqblk,
+	setdqblk:	set_dqblk,
+};
diff -Naur linux-2410ac8/fs/noquot.c linux-2410ac8-quota/fs/noquot.c
--- linux-2410ac8/fs/noquot.c	Mon Oct  8 13:27:00 2001
+++ linux-2410ac8-quota/fs/noquot.c	Thu Jan  1 10:00:00 1970
@@ -1,20 +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);
-}
-
-void shrink_dqcache_memory(int priority, unsigned int gfp_mask)
-{
-	;
-}
diff -Naur linux-2410ac8/fs/quota.c linux-2410ac8-quota/fs/quota.c
--- linux-2410ac8/fs/quota.c	Thu Jan  1 10:00:00 1970
+++ linux-2410ac8-quota/fs/quota.c	Mon Oct  8 18:15:41 2001
@@ -0,0 +1,216 @@
+/*
+ * Quota code necessary even when VFS quota support is not compiled
+ * into the kernel.  Allows filesystems to implement their own form
+ * of quota if they wish.  The interesting stuff is over in dquot.c,
+ * living here are symbols for initial quotactl(2) handling, sysctl
+ * 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;
+
+#ifndef CONFIG_QUOTA
+void shrink_dqcache_memory(int priority, unsigned int mask)
+{
+	return;
+}
+#endif
+
+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 out;
+
+	/* 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 out;
+	if (type >= MAXQUOTAS)
+		goto out;
+
+	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 out;
+
+		default:
+			if (!capable(CAP_SYS_ADMIN))
+				goto out;
+	}
+
+	ret = -ENODEV;
+	if (!special)
+		goto out;
+	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 = -ENOSYS;
+	if (!sb->s_qop) {
+		drop_super(sb);
+		goto out;
+	}
+
+	ret = 0;
+out:
+	if (ret)
+		return ERR_PTR(ret);
+	return NULL;
+}
+
+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->sync)
+				ret = sb->s_qop->sync(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, id, type, &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, id, type, &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, type, u.flags, cmds);
+			break;
+
+		case Q_XGETQSTAT:
+			if (sb->s_qop->getxstate)
+				ret = sb->s_qop->getxstate(sb, type, &u.fqs);
+			ret = -EFAULT;
+			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, &u.fdq);
+			break;
+
+		case Q_XGETQUOTA:
+			if (sb->s_qop->getxquota)
+				ret = sb->s_qop->getxquota(sb, type, &u.fdq);
+			ret = -EFAULT;
+			if (!ret && copy_to_user(addr, &u.fqs, sizeof(u.fdq)))
+				ret = -EFAULT;
+			break;
+
+		default:
+	}
+	drop_super(sb);
+	unlock_kernel();
+	return ret;
+}
diff -Naur linux-2410ac8/fs/super.c linux-2410ac8-quota/fs/super.c
--- linux-2410ac8/fs/super.c	Mon Oct  8 13:27:00 2001
+++ linux-2410ac8-quota/fs/super.c	Mon Oct  8 13:29:31 2001
@@ -453,6 +453,7 @@
 	s->s_bdev = bdev;
 	s->s_flags = flags;
 	s->s_type = type;
+	s->s_qop = sb_generic_quota_ops;
 	spin_lock(&sb_lock);
 	list_add (&s->s_list, super_blocks.prev);
 	list_add (&s->s_instances, &type->fs_supers);
@@ -473,6 +474,7 @@
 	s->s_dev = 0;
 	s->s_bdev = 0;
 	s->s_type = NULL;
+	s->s_qop = NULL;
 	unlock_super(s);
 	spin_lock(&sb_lock);
 	list_del(&s->s_list);
@@ -604,6 +606,7 @@
 	s->s_bdev = bdev;
 	s->s_flags = flags;
 	s->s_type = fs_type;
+	s->s_qop = sb_generic_quota_ops;
 	list_add (&s->s_list, super_blocks.prev);
 	list_add (&s->s_instances, &fs_type->fs_supers);
 	s->s_count += S_BIAS;
@@ -623,6 +626,7 @@
 	s->s_dev = 0;
 	s->s_bdev = 0;
 	s->s_type = NULL;
+	s->s_qop = NULL;
 	unlock_super(s);
 	spin_lock(&sb_lock);
 	list_del(&s->s_list);
@@ -687,6 +691,7 @@
 		s->s_dev = dev;
 		s->s_flags = flags;
 		s->s_type = fs_type;
+		s->s_qop = sb_generic_quota_ops;
 		list_add (&s->s_list, super_blocks.prev);
 		list_add (&s->s_instances, &fs_type->fs_supers);
 		s->s_count += S_BIAS;
@@ -702,6 +707,7 @@
 		s->s_dev = 0;
 		s->s_bdev = 0;
 		s->s_type = NULL;
+		s->s_qop = NULL;
 		unlock_super(s);
 		spin_lock(&sb_lock);
 		list_del(&s->s_list);
@@ -757,6 +763,7 @@
 	sb->s_bdev = NULL;
 	put_filesystem(fs);
 	sb->s_type = NULL;
+	sb->s_qop = NULL;
 	unlock_super(sb);
 	unlock_kernel();
 	if (bdev)
diff -Naur linux-2410ac8/include/linux/fs.h linux-2410ac8-quota/include/linux/fs.h
--- linux-2410ac8/include/linux/fs.h	Mon Oct  8 13:27:00 2001
+++ linux-2410ac8-quota/include/linux/fs.h	Mon Oct  8 18:19:06 2001
@@ -376,6 +376,7 @@
 /*
  * Includes for diskquotas and mount structures.
  */
+#include <linux/xqm.h>
 #include <linux/quota.h>
 #include <linux/mount.h>
 
@@ -659,6 +660,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 (*sync)(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 (*setxstate)(struct super_block *, short, unsigned int, int);
+	int (*getxstate)(struct super_block *, short, struct fs_quota_stat *);
+	int (*setxquota)(struct super_block *, short, struct fs_disk_quota *);
+	int (*getxquota)(struct super_block *, short, struct fs_disk_quota *);
+};
+
 /*
  *	Umount options
  */
@@ -720,6 +735,7 @@
 	struct block_device	*s_bdev;
 	struct list_head	s_instances;
 	struct quota_info	s_dquot;	/* Diskquota specific options */
+	struct quota_operations	*s_qop;
 
 	union {
 		struct minix_sb_info	minix_sb;
diff -Naur linux-2410ac8/include/linux/quota.h linux-2410ac8-quota/include/linux/quota.h
--- linux-2410ac8/include/linux/quota.h	Mon Oct  8 15:30:03 2001
+++ linux-2410ac8-quota/include/linux/quota.h	Mon Oct  8 18:04:05 2001
@@ -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
@@ -253,13 +253,6 @@
 #define dq_bhardlimit dq_dqb.dqb_bhardlimit
 #define dq_itime dq_dqb.dqb_itime
 #define dq_btime dq_dqb.dqb_btime
-
-/*
- * Flags used for set_dqblk.
- */
-#define SET_QUOTA         0x01
-#define SET_USE           0x02
-#define SET_QLIMIT        0x04
 
 #define QUOTA_OK          0
 #define NO_QUOTA          1
diff -Naur linux-2410ac8/include/linux/quotaops.h linux-2410ac8-quota/include/linux/quotaops.h
--- linux-2410ac8/include/linux/quotaops.h	Mon Oct  8 13:27:00 2001
+++ linux-2410ac8-quota/include/linux/quotaops.h	Mon Oct  8 18:26:56 2001
@@ -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.
  */
@@ -166,6 +169,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 linux-2410ac8/include/linux/sysctl.h linux-2410ac8-quota/include/linux/sysctl.h
--- linux-2410ac8/include/linux/sysctl.h	Mon Oct  8 13:27:00 2001
+++ linux-2410ac8-quota/include/linux/sysctl.h	Mon Oct  8 18:04:06 2001
@@ -535,7 +535,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 linux-2410ac8/include/linux/xqm.h linux-2410ac8-quota/include/linux/xqm.h
--- linux-2410ac8/include/linux/xqm.h	Thu Jan  1 10:00:00 1970
+++ linux-2410ac8-quota/include/linux/xqm.h	Mon Oct  8 18:04:05 2001
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2000 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 of the GNU 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 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 */
+#define Q_XDEBUG	XQM_CMD(0x7)	/* do internal consistency checks */
+
+/*
+ * 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] 7+ messages in thread

* Re: Quotactl change
  2001-10-08 10:34   ` Nathan Scott
@ 2001-10-09  7:03     ` Alexander Viro
  2001-10-09  7:34     ` Jan Kara
  1 sibling, 0 replies; 7+ messages in thread
From: Alexander Viro @ 2001-10-09  7:03 UTC (permalink / raw)
  To: Nathan Scott; +Cc: Jan Kara, Alan Cox, linux-kernel, linux-xfs



On Mon, 8 Oct 2001, Nathan Scott wrote:

> hi all,
> 
> Al - is the attached patch more along the lines of what you
> were after?

Quota side looks sane.  fs/super.c one is an overkill - just set default in
alloc_super().  There is no need to bother with resetting it - in the
places where you do it superblock is already deactivated, so get_super()
in quotactl will not return it and at that point there should be no inodes
left from that filesystem.


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

* Re: Quotactl change
  2001-10-08 10:34   ` Nathan Scott
  2001-10-09  7:03     ` Alexander Viro
@ 2001-10-09  7:34     ` Jan Kara
  2001-10-09 12:21       ` Nathan Scott
  1 sibling, 1 reply; 7+ messages in thread
From: Jan Kara @ 2001-10-09  7:34 UTC (permalink / raw)
  To: Nathan Scott; +Cc: Alexander Viro, Alan Cox, linux-kernel, linux-xfs

  Hello,

> Al - is the attached patch more along the lines of what you
> were after?
> 
> Jan - I think this is actually alot closer to what you were
> talking about when we last discussed this.  Can you see any
> problems from a VFS quota point of view here?  I had to make
> small interface changes to a couple of the dquot.c routines
> to make this simpler/more uniform in places - could you have
> cross-check those for me?
  I see two problems:

1) You changed interface do dquot_sync() - so you should also
   change DQUOT_SYNC() macro in quotaops.h (rename argument) and
   all callers of DQUOT_SYNC() macro...

2) It seems to me that validate_quotactl() will actually never return
   superblock - instead of 'ret = 0;' there should be 'return sb;'
   and that test 'if (ret)' should be removed....


								Honza

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

* Re: Quotactl change
  2001-10-09  7:34     ` Jan Kara
@ 2001-10-09 12:21       ` Nathan Scott
  0 siblings, 0 replies; 7+ messages in thread
From: Nathan Scott @ 2001-10-09 12:21 UTC (permalink / raw)
  To: Alexander Viro, Jan Kara; +Cc: Alan Cox, linux-kernel, linux-xfs

On Tue, Oct 09, 2001 at 03:03:49AM -0400, Alexander Viro wrote:
> 
> Quota side looks sane.  fs/super.c one is an overkill...
> 

On Tue, Oct 09, 2001 at 09:34:25AM +0200, Jan Kara wrote:
>   I see two problems...
> 

Thanks - these three issues should be resolved now.  I'll
bang on this some more tomorrow, but this should just about
do it, I think.

cheers.

-- 
Nathan


diff -Naur linux-2410ac8/fs/Makefile linux-2410ac8-quota/fs/Makefile
--- linux-2410ac8/fs/Makefile	Mon Oct  8 13:26:59 2001
+++ linux-2410ac8-quota/fs/Makefile	Mon Oct  8 19:45:36 2001
@@ -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 jbd-kernel.o namespace.o
+		filesystems.o jbd-kernel.o namespace.o quota.o
 
 ifeq ($(CONFIG_QUOTA),y)
 obj-y += dquot.o
-else
-obj-y += noquot.o
 endif
 
 subdir-$(CONFIG_PROC_FS)	+= proc
diff -Naur linux-2410ac8/fs/dquot.c linux-2410ac8-quota/fs/dquot.c
--- linux-2410ac8/fs/dquot.c	Mon Oct  8 13:26:59 2001
+++ linux-2410ac8-quota/fs/dquot.c	Tue Oct  9 20:08:05 2001
@@ -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;
@@ -1019,6 +1021,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)
 {
@@ -1477,25 +1484,21 @@
  * 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)) {
+		if (op == Q_SETQUOTA || op == Q_SETQLIM) {
 			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 ((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)
@@ -1529,77 +1532,85 @@
 	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);
 			break;
-		case ISET_GRACE:
+		case Q_SETGRACE:
 			dqopt->info[type].dqi_bgrace = info.dqi_bgrace;
 			dqopt->info[type].dqi_igrace = info.dqi_igrace;
 			break;
-		case ISET_ALL:
+		case Q_SETINFO:
 			info.dqi_flags &= ~DQF_MASK;
 			memcpy(dqopt->info + type, &info, sizeof(struct mem_dqinfo));
 			break;
@@ -1886,6 +1897,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);
@@ -1939,9 +1951,6 @@
 	short cnt;
 	struct quota_info *dqopt = sb_dqopt(sb);
 
-	if (!sb)
-		goto out;
-
 	/* We need to serialize quota_off() for device */
 	down(&dqopt->dqoff_sem);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1963,7 +1972,6 @@
 		fput(filp);
 	}	
 	up(&dqopt->dqoff_sem);
-out:
 	return 0;
 }
 
@@ -2044,114 +2052,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 ((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 linux-2410ac8/fs/noquot.c linux-2410ac8-quota/fs/noquot.c
--- linux-2410ac8/fs/noquot.c	Mon Oct  8 13:27:00 2001
+++ linux-2410ac8-quota/fs/noquot.c	Thu Jan  1 10:00:00 1970
@@ -1,20 +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);
-}
-
-void shrink_dqcache_memory(int priority, unsigned int gfp_mask)
-{
-	;
-}
diff -Naur linux-2410ac8/fs/quota.c linux-2410ac8-quota/fs/quota.c
--- linux-2410ac8/fs/quota.c	Thu Jan  1 10:00:00 1970
+++ linux-2410ac8-quota/fs/quota.c	Tue Oct  9 20:44:43 2001
@@ -0,0 +1,212 @@
+/*
+ * Quota code necessary even when VFS quota support is not compiled
+ * into the kernel.  Allows filesystems to implement their own form
+ * of quota if they wish.  The interesting stuff is over in dquot.c,
+ * living here are symbols for initial quotactl(2) handling, sysctl
+ * 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;
+
+#ifndef CONFIG_QUOTA
+void shrink_dqcache_memory(int priority, unsigned int mask)
+{
+	return;
+}
+#endif
+
+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, id, type, &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, id, type, &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, type, u.flags, cmds);
+			break;
+
+		case Q_XGETQSTAT:
+			if (sb->s_qop->getxstate)
+				ret = sb->s_qop->getxstate(sb, type, &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, &u.fdq);
+			break;
+
+		case Q_XGETQUOTA:
+			if (sb->s_qop->getxquota)
+				ret = sb->s_qop->getxquota(sb, type, &u.fdq);
+			if (!ret && copy_to_user(addr, &u.fqs, sizeof(u.fdq)))
+				ret = -EFAULT;
+			break;
+
+		default:
+	}
+	drop_super(sb);
+	unlock_kernel();
+	return ret;
+}
diff -Naur linux-2410ac8/fs/super.c linux-2410ac8-quota/fs/super.c
--- linux-2410ac8/fs/super.c	Mon Oct  8 13:27:00 2001
+++ linux-2410ac8-quota/fs/super.c	Tue Oct  9 21:34:49 2001
@@ -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 linux-2410ac8/include/linux/fs.h linux-2410ac8-quota/include/linux/fs.h
--- linux-2410ac8/include/linux/fs.h	Mon Oct  8 13:27:00 2001
+++ linux-2410ac8-quota/include/linux/fs.h	Tue Oct  9 20:24:42 2001
@@ -376,6 +376,7 @@
 /*
  * Includes for diskquotas and mount structures.
  */
+#include <linux/xqm.h>
 #include <linux/quota.h>
 #include <linux/mount.h>
 
@@ -659,6 +660,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 *, short, struct fs_quota_stat *);
+	int (*setxstate)(struct super_block *, short, unsigned int, int);
+	int (*getxquota)(struct super_block *, short, struct fs_disk_quota *);
+	int (*setxquota)(struct super_block *, short, struct fs_disk_quota *);
+};
+
 /*
  *	Umount options
  */
@@ -720,6 +735,7 @@
 	struct block_device	*s_bdev;
 	struct list_head	s_instances;
 	struct quota_info	s_dquot;	/* Diskquota specific options */
+	struct quota_operations	*s_qop;
 
 	union {
 		struct minix_sb_info	minix_sb;
diff -Naur linux-2410ac8/include/linux/quota.h linux-2410ac8-quota/include/linux/quota.h
--- linux-2410ac8/include/linux/quota.h	Mon Oct  8 15:30:03 2001
+++ linux-2410ac8-quota/include/linux/quota.h	Mon Oct  8 18:04:05 2001
@@ -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
@@ -253,13 +253,6 @@
 #define dq_bhardlimit dq_dqb.dqb_bhardlimit
 #define dq_itime dq_dqb.dqb_itime
 #define dq_btime dq_dqb.dqb_btime
-
-/*
- * Flags used for set_dqblk.
- */
-#define SET_QUOTA         0x01
-#define SET_USE           0x02
-#define SET_QLIMIT        0x04
 
 #define QUOTA_OK          0
 #define NO_QUOTA          1
diff -Naur linux-2410ac8/include/linux/quotaops.h linux-2410ac8-quota/include/linux/quotaops.h
--- linux-2410ac8/include/linux/quotaops.h	Mon Oct  8 13:27:00 2001
+++ linux-2410ac8-quota/include/linux/quotaops.h	Mon Oct  8 18:26:56 2001
@@ -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.
  */
@@ -166,6 +169,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 linux-2410ac8/include/linux/sysctl.h linux-2410ac8-quota/include/linux/sysctl.h
--- linux-2410ac8/include/linux/sysctl.h	Mon Oct  8 13:27:00 2001
+++ linux-2410ac8-quota/include/linux/sysctl.h	Mon Oct  8 18:04:06 2001
@@ -535,7 +535,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 linux-2410ac8/include/linux/xqm.h linux-2410ac8-quota/include/linux/xqm.h
--- linux-2410ac8/include/linux/xqm.h	Thu Jan  1 10:00:00 1970
+++ linux-2410ac8-quota/include/linux/xqm.h	Mon Oct  8 18:04:05 2001
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2000 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 of the GNU 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 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] 7+ messages in thread

end of thread, other threads:[~2001-10-09 12:23 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-10-06 13:07 Quotactl change Jan Kara
2001-10-06 18:25 ` Alexander Viro
2001-10-08  2:19   ` Nathan Scott
2001-10-08 10:34   ` Nathan Scott
2001-10-09  7:03     ` Alexander Viro
2001-10-09  7:34     ` Jan Kara
2001-10-09 12:21       ` Nathan Scott

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).