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,
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.
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
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
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.
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
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 <[email protected]> 12/2000
*
* New quotafile format
- * Alocation units changed to bytes
+ * Allocation units changed to bytes
* Jan Kara, <[email protected]>, 2000
*
+ * Reworked the quotactl interface for filesystem-specific quota
+ * Nathan Scott <[email protected]> and Jan Kara <[email protected]>, 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 */