xfs
[Top] [All Lists]

Re: Quota & XFS patch

To: Shawn Starr <spstarr@xxxxxxxx>
Subject: Re: Quota & XFS patch
From: Shawn Starr <spstarr@xxxxxxxx>
Date: 27 Feb 2002 16:00:13 -0500
Cc: Jan Kara <jack@xxxxxx>, xfs <linux-xfs@xxxxxxxxxxx>
In-reply-to: <1014837395.3448.42.camel@unaropia>
References: <20020227160938.GA22460@xxxxxxxxxxxxxxxxxxxxxxxx> <1014837395.3448.42.camel@unaropia>
Sender: owner-linux-xfs@xxxxxxxxxxx
Why not merge into XFS CVS tree?

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



<Prev in Thread] Current Thread [Next in Thread>
  • Re: Quota & XFS patch, Shawn Starr <=