]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] [7/13] quota-7-quotactl
authorJan Kara <jack@suse.cz>
Mon, 20 May 2002 02:34:20 +0000 (19:34 -0700)
committerLinus Torvalds <torvalds@penguin.transmeta.com>
Mon, 20 May 2002 02:34:20 +0000 (19:34 -0700)
This is probably the largest chunk in quota patches. It removes old quotactl interface
and implements new one. New interface should not need arch specific conversions so they
are removed. All quota interface stuff is moved to quota.c so we can
easily separate things which should be compiled even if quota is disabled (mainly
because XFS needs some interface even if standard VFS quota is disabled).
Callbacks to filesystem on quota_on() and quota_off() are implemented (needed by Ext3),
quota operations callbacks are now set in super.c on superblock initialization and
not on quota_on(). This way it starts to make sense to have callbacks on alloc_space(),
alloc_inode() etc. as filesystem can override them on read_super(). This will be used
later for implementing journalled quota.

14 files changed:
arch/ia64/ia32/ia32_entry.S
arch/ia64/ia32/sys_ia32.c
arch/s390x/kernel/linux32.c
arch/s390x/kernel/wrapper32.S
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/systbls.S
fs/Makefile
fs/dquot.c
fs/quota.c [new file with mode: 0644]
fs/super.c
include/linux/fs.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/xqm.h [new file with mode: 0644]

index f3e7e950b7ac0a61b9a2f5cda429946e146dbee8..f9595d3f43ed7a9e0699e520beedfc27d85798f8 100644 (file)
@@ -310,7 +310,7 @@ ia32_syscall_table:
        data8 sys32_ni_syscall  /* init_module */
        data8 sys32_ni_syscall  /* delete_module */
        data8 sys32_ni_syscall  /* get_kernel_syms */  /* 130 */
-       data8 sys32_quotactl
+       data8 sys_quotactl
        data8 sys_getpgid
        data8 sys_fchdir
        data8 sys32_ni_syscall  /* sys_bdflush */
index 0bcd16ac271e72012275fc51019fca58c936d1b8..c3852b487a11ff5fb9b292868ffa9a0066d96e81 100644 (file)
@@ -3669,60 +3669,6 @@ getname32 (const char *filename)
        return result;
 }
 
-struct dqblk32 {
-       __u32 dqb_bhardlimit;
-       __u32 dqb_bsoftlimit;
-       __u32 dqb_curblocks;
-       __u32 dqb_ihardlimit;
-       __u32 dqb_isoftlimit;
-       __u32 dqb_curinodes;
-       __kernel_time_t32 dqb_btime;
-       __kernel_time_t32 dqb_itime;
-};
-
-asmlinkage long
-sys32_quotactl (int cmd, unsigned int special, int id, struct dqblk32 *addr)
-{
-       extern asmlinkage long sys_quotactl (int, const char *, int, caddr_t);
-       int cmds = cmd >> SUBCMDSHIFT;
-       mm_segment_t old_fs;
-       struct dqblk d;
-       char *spec;
-       long err;
-
-       switch (cmds) {
-             case Q_GETQUOTA:
-               break;
-             case Q_SETQUOTA:
-             case Q_SETUSE:
-             case Q_SETQLIM:
-               if (copy_from_user (&d, addr, sizeof(struct dqblk32)))
-                       return -EFAULT;
-               d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
-               d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
-               break;
-             default:
-               return sys_quotactl(cmd, (void *) A(special), id, (caddr_t) addr);
-       }
-       spec = getname32((void *) A(special));
-       err = PTR_ERR(spec);
-       if (IS_ERR(spec))
-               return err;
-       old_fs = get_fs ();
-       set_fs(KERNEL_DS);
-       err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
-       set_fs(old_fs);
-       putname(spec);
-       if (cmds == Q_GETQUOTA) {
-               __kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-               ((struct dqblk32 *)&d)->dqb_itime = i;
-               ((struct dqblk32 *)&d)->dqb_btime = b;
-               if (copy_to_user(addr, &d, sizeof(struct dqblk32)))
-                       return -EFAULT;
-       }
-       return err;
-}
-
 asmlinkage long
 sys32_sched_rr_get_interval (pid_t pid, struct timespec32 *interval)
 {
index a125f2d41043e66dae4753474d5454ca0fe4ab58..e06f1958dd108dc638d706ca3106dcce4ecb23a5 100644 (file)
@@ -897,64 +897,6 @@ asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long a
        return sys32_fcntl(fd, cmd, arg);
 }
 
-struct mem_dqblk32 {
-    __u32 dqb_ihardlimit;
-    __u32 dqb_isoftlimit;
-    __u32 dqb_curinodes;
-    __u32 dqb_bhardlimit;
-    __u32 dqb_bsoftlimit;
-    __u64 dqb_curspace;
-    __kernel_time_t32 dqb_btime;
-    __kernel_time_t32 dqb_itime;
-};
-                                
-extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, __kernel_caddr_t addr);
-
-asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
-{
-       int cmds = cmd >> SUBCMDSHIFT;
-       int err;
-       struct mem_dqblk d;
-       mm_segment_t old_fs;
-       char *spec;
-       
-       switch (cmds) {
-       case Q_GETQUOTA:
-               break;
-       case Q_SETQUOTA:
-       case Q_SETUSE:
-       case Q_SETQLIM:
-               if (copy_from_user (&d, (struct mem_dqblk32 *)addr,
-                                   sizeof (struct mem_dqblk32)))
-                       return -EFAULT;
-               d.dqb_itime = ((struct mem_dqblk32 *)&d)->dqb_itime;
-               d.dqb_btime = ((struct mem_dqblk32 *)&d)->dqb_btime;
-               break;
-       default:
-               return sys_quotactl(cmd, special,
-                                   id, (__kernel_caddr_t)addr);
-       }
-       spec = getname (special);
-       err = PTR_ERR(spec);
-       if (IS_ERR(spec)) return err;
-       old_fs = get_fs ();
-       set_fs (KERNEL_DS);
-       err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d);
-       set_fs (old_fs);
-       putname (spec);
-       if (err)
-               return err;
-       if (cmds == Q_GETQUOTA) {
-               __kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-               ((struct mem_dqblk32 *)&d)->dqb_itime = i;
-               ((struct mem_dqblk32 *)&d)->dqb_btime = b;
-               if (copy_to_user ((struct mem_dqblk32 *)addr, &d,
-                                 sizeof (struct mem_dqblk32)))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
 static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
        int err;
index a11ee19b21ffb3691d17c48e45c25ededc3841ae..8a66558332b1fffae5388dcfd876d4a054bf544c 100644 (file)
@@ -586,7 +586,7 @@ sys32_quotactl_wrapper:
        llgtr   %r3,%r3                 # const char *
        lgfr    %r4,%r4                 # int
        llgtr   %r5,%r5                 # caddr_t
-       jg      sys32_quotactl          # branch to system call
+       jg      sys_quotactl            # branch to system call
 
        .globl  sys32_getpgid_wrapper 
 sys32_getpgid_wrapper:
index 0e4720e339666a7494fad5f3b655539026a6388d..224387833d548b59cce275a5d91f00fd31b55e18 100644 (file)
@@ -889,62 +889,6 @@ asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long a
        return sys32_fcntl(fd, cmd, arg);
 }
 
-struct dqblk32 {
-    __u32 dqb_bhardlimit;
-    __u32 dqb_bsoftlimit;
-    __u32 dqb_curblocks;
-    __u32 dqb_ihardlimit;
-    __u32 dqb_isoftlimit;
-    __u32 dqb_curinodes;
-    __kernel_time_t32 dqb_btime;
-    __kernel_time_t32 dqb_itime;
-};
-                                
-extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
-
-asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
-{
-       int cmds = cmd >> SUBCMDSHIFT;
-       int err;
-       struct dqblk d;
-       mm_segment_t old_fs;
-       char *spec;
-       
-       switch (cmds) {
-       case Q_GETQUOTA:
-               break;
-       case Q_SETQUOTA:
-       case Q_SETUSE:
-       case Q_SETQLIM:
-               if (copy_from_user (&d, (struct dqblk32 *)addr,
-                                   sizeof (struct dqblk32)))
-                       return -EFAULT;
-               d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
-               d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
-               break;
-       default:
-               return sys_quotactl(cmd, special,
-                                   id, (caddr_t)addr);
-       }
-       spec = getname (special);
-       err = PTR_ERR(spec);
-       if (IS_ERR(spec)) return err;
-       old_fs = get_fs ();
-       set_fs (KERNEL_DS);
-       err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
-       set_fs (old_fs);
-       putname (spec);
-       if (cmds == Q_GETQUOTA) {
-               __kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-               ((struct dqblk32 *)&d)->dqb_itime = i;
-               ((struct dqblk32 *)&d)->dqb_btime = b;
-               if (copy_to_user ((struct dqblk32 *)addr, &d,
-                                 sizeof (struct dqblk32)))
-                       return -EFAULT;
-       }
-       return err;
-}
-
 static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
        int err;
index b7b5414167bd9d50d4e29b18d1ea36e84c95969b..6138ce2fca94c162b693796252e5cc662a3911a5 100644 (file)
@@ -52,7 +52,7 @@ sys_call_table32:
 /*150*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
        .word sys32_fcntl64, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
 /*160*/        .word sys32_sched_setaffinity, sys32_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-       .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_setxattr
+       .word sys_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_setxattr
 /*170*/        .word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
        .word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/        .word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys32_sigpending, sys32_query_module
@@ -194,7 +194,7 @@ sunos_sys_table:
        .word sunos_getdirentries, sys32_statfs, sys32_fstatfs
        .word sys_oldumount, sunos_nosys, sunos_nosys
        .word sys_getdomainname, sys_setdomainname
-       .word sunos_nosys, sys32_quotactl, sunos_nosys
+       .word sunos_nosys, sys_quotactl, sunos_nosys
        .word sunos_mount, sys_ustat, sunos_semsys
        .word sunos_nosys, sunos_shmsys, sunos_audit
        .word sunos_nosys, sunos_getdents, sys_setsid
index 83769de6e2e4f3d864520f7de082312cfbebc1d2..e843c709297e1a0ea5436f0867d767f0195565a9 100644 (file)
@@ -15,7 +15,7 @@ obj-y :=      open.o read_write.o devices.o file_table.o buffer.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 xattr.o libfs.o \
-               fs-writeback.o
+               fs-writeback.o quota.o
 
 ifneq ($(CONFIG_NFSD),n)
 ifneq ($(CONFIG_NFSD),)
index 1503708a465744a7686f2ce391a6a1909056fbd8..b6125801dd94cf135b19226cd2f6cdd020315d0a 100644 (file)
 #include <linux/sysctl.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/proc_fs.h>
 
 #include <asm/uaccess.h>
 
-int nr_dquots, nr_free_dquots;
-
 static char *quotatypes[] = INITQFNAMES;
 static struct quota_format_type *quota_formats;        /* List of registered formats */
 
@@ -97,10 +96,18 @@ static struct quota_format_type *find_quota_format(int id)
 
        lock_kernel();
        for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next);
+       if (actqf && !try_inc_mod_count(actqf->qf_owner))
+               actqf = NULL;
        unlock_kernel();
        return actqf;
 }
 
+static void put_quota_format(struct quota_format_type *fmt)
+{
+       if (fmt->qf_owner)
+               __MOD_DEC_USE_COUNT(fmt->qf_owner);
+}
+
 /*
  * Dquot List Management:
  * The quota code uses three lists for dquot management: the inuse_list,
@@ -141,27 +148,11 @@ static LIST_HEAD(inuse_list);
 static LIST_HEAD(free_dquots);
 static struct list_head dquot_hash[NR_DQHASH];
 
-static struct dqstats dqstats;
+struct dqstats dqstats;
 
 static void dqput(struct dquot *);
 static struct dquot *dqduplicate(struct dquot *);
 
-static inline char is_enabled(struct quota_info *dqopt, short type)
-{
-       switch (type) {
-               case USRQUOTA:
-                       return((dqopt->flags & DQUOT_USR_ENABLED) != 0);
-               case GRPQUOTA:
-                       return((dqopt->flags & DQUOT_GRP_ENABLED) != 0);
-       }
-       return(0);
-}
-
-static inline char sb_has_quota_enabled(struct super_block *sb, short type)
-{
-       return is_enabled(sb_dqopt(sb), type);
-}
-
 static inline void get_dquot_ref(struct dquot *dquot)
 {
        dquot->dq_count++;
@@ -405,6 +396,7 @@ restart:
                dqput(dquot);
                goto restart;
        }
+       /* FIXME: Here we should also sync all file info */
        dqstats.syncs++;
        unlock_kernel();
        return 0;
@@ -619,9 +611,6 @@ static void add_dquot_ref(struct super_block *sb, short type)
 {
        struct list_head *p;
 
-       if (!sb->dq_op)
-               return; /* nothing to do */
-
 restart:
        file_list_lock();
        list_for_each(p, &sb->s_files) {
@@ -699,36 +688,36 @@ void put_dquot_list(struct list_head *tofree_head)
 
 static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
 {
-       dquot->dq_curinodes += number;
+       dquot->dq_dqb.dqb_curinodes += number;
        mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_incr_space(struct dquot *dquot, qsize_t number)
 {
-       dquot->dq_curspace += number;
+       dquot->dq_dqb.dqb_curspace += number;
        mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number)
 {
-       if (dquot->dq_curinodes > number)
-               dquot->dq_curinodes -= number;
+       if (dquot->dq_dqb.dqb_curinodes > number)
+               dquot->dq_dqb.dqb_curinodes -= number;
        else
-               dquot->dq_curinodes = 0;
-       if (dquot->dq_curinodes < dquot->dq_isoftlimit)
-               dquot->dq_itime = (time_t) 0;
+               dquot->dq_dqb.dqb_curinodes = 0;
+       if (dquot->dq_dqb.dqb_curinodes < dquot->dq_dqb.dqb_isoftlimit)
+               dquot->dq_dqb.dqb_itime = (time_t) 0;
        dquot->dq_flags &= ~DQ_INODES;
        mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_decr_space(struct dquot *dquot, qsize_t number)
 {
-       if (dquot->dq_curspace > number)
-               dquot->dq_curspace -= number;
+       if (dquot->dq_dqb.dqb_curspace > number)
+               dquot->dq_dqb.dqb_curspace -= number;
        else
-               dquot->dq_curspace = 0;
-       if (toqb(dquot->dq_curspace) < dquot->dq_bsoftlimit)
-               dquot->dq_btime = (time_t) 0;
+               dquot->dq_dqb.dqb_curspace = 0;
+       if (toqb(dquot->dq_dqb.dqb_curspace) < dquot->dq_dqb.dqb_bsoftlimit)
+               dquot->dq_dqb.dqb_btime = (time_t) 0;
        dquot->dq_flags &= ~DQ_BLKS;
        mark_dquot_dirty(dquot);
 }
@@ -812,26 +801,26 @@ static int check_idq(struct dquot *dquot, ulong inodes, char *warntype)
        if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)
                return QUOTA_OK;
 
-       if (dquot->dq_ihardlimit &&
-          (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit &&
+       if (dquot->dq_dqb.dqb_ihardlimit &&
+          (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_ihardlimit &&
             !ignore_hardlimit(dquot)) {
                *warntype = IHARDWARN;
                return NO_QUOTA;
        }
 
-       if (dquot->dq_isoftlimit &&
-          (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
-           dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime &&
+       if (dquot->dq_dqb.dqb_isoftlimit &&
+          (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit &&
+           dquot->dq_dqb.dqb_itime && CURRENT_TIME >= dquot->dq_dqb.dqb_itime &&
             !ignore_hardlimit(dquot)) {
                *warntype = ISOFTLONGWARN;
                return NO_QUOTA;
        }
 
-       if (dquot->dq_isoftlimit &&
-          (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
-           dquot->dq_itime == 0) {
+       if (dquot->dq_dqb.dqb_isoftlimit &&
+          (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit &&
+           dquot->dq_dqb.dqb_itime == 0) {
                *warntype = ISOFTWARN;
-               dquot->dq_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+               dquot->dq_dqb.dqb_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
        }
 
        return QUOTA_OK;
@@ -843,29 +832,29 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
        if (space <= 0 || dquot->dq_flags & DQ_FAKE)
                return QUOTA_OK;
 
-       if (dquot->dq_bhardlimit &&
-          toqb(dquot->dq_curspace + space) > dquot->dq_bhardlimit &&
+       if (dquot->dq_dqb.dqb_bhardlimit &&
+          toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit &&
             !ignore_hardlimit(dquot)) {
                if (!prealloc)
                        *warntype = BHARDWARN;
                return NO_QUOTA;
        }
 
-       if (dquot->dq_bsoftlimit &&
-          toqb(dquot->dq_curspace + space) > dquot->dq_bsoftlimit &&
-           dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime &&
+       if (dquot->dq_dqb.dqb_bsoftlimit &&
+          toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit &&
+           dquot->dq_dqb.dqb_btime && CURRENT_TIME >= dquot->dq_dqb.dqb_btime &&
             !ignore_hardlimit(dquot)) {
                if (!prealloc)
                        *warntype = BSOFTLONGWARN;
                return NO_QUOTA;
        }
 
-       if (dquot->dq_bsoftlimit &&
-          toqb(dquot->dq_curspace + space) > dquot->dq_bsoftlimit &&
-           dquot->dq_btime == 0) {
+       if (dquot->dq_dqb.dqb_bsoftlimit &&
+          toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit &&
+           dquot->dq_dqb.dqb_btime == 0) {
                if (!prealloc) {
                        *warntype = BSOFTWARN;
-                       dquot->dq_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
+                       dquot->dq_dqb.dqb_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
                }
                else
                        /*
@@ -1199,10 +1188,9 @@ extern void remove_dquot_ref(struct super_block *, short);
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
-int quota_off(struct super_block *sb, short type)
+int vfs_quota_off(struct super_block *sb, int type)
 {
-       struct file *filp;
-       short cnt;
+       int cnt;
        struct quota_info *dqopt = sb_dqopt(sb);
 
        lock_kernel();
@@ -1222,17 +1210,17 @@ int quota_off(struct super_block *sb, short type)
                remove_dquot_ref(sb, cnt);
                invalidate_dquots(sb, cnt);
                 if (info_dirty(&dqopt->info[cnt]))
-                        dqopt->ops[cnt]->write_file_info(sb, cnt);
+                       dqopt->ops[cnt]->write_file_info(sb, cnt);
                if (dqopt->ops[cnt]->free_file_info)
                        dqopt->ops[cnt]->free_file_info(sb, cnt);
+               put_quota_format(dqopt->info[cnt].dqi_format);
 
-               filp = dqopt->files[cnt];
+               fput(dqopt->files[cnt]);
                dqopt->files[cnt] = (struct file *)NULL;
                dqopt->info[cnt].dqi_flags = 0;
                dqopt->info[cnt].dqi_igrace = 0;
                dqopt->info[cnt].dqi_bgrace = 0;
                dqopt->ops[cnt] = NULL;
-               fput(filp);
        }       
        up(&dqopt->dqoff_sem);
 out:
@@ -1240,9 +1228,9 @@ out:
        return 0;
 }
 
-static int quota_on(struct super_block *sb, int type, int format_id, char *path)
+int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
 {
-       struct file *f;
+       struct file *f = NULL;
        struct inode *inode;
        struct quota_info *dqopt = sb_dqopt(sb);
        struct quota_format_type *fmt = find_quota_format(format_id);
@@ -1250,8 +1238,10 @@ static int quota_on(struct super_block *sb, int type, int format_id, char *path)
 
        if (!fmt)
                return -EINVAL;
-       if (is_enabled(dqopt, type))
-               return -EBUSY;
+       if (is_enabled(dqopt, type)) {
+               error = -EBUSY;
+               goto out_fmt;
+       }
 
        down(&dqopt->dqoff_sem);
 
@@ -1276,10 +1266,9 @@ static int quota_on(struct super_block *sb, int type, int format_id, char *path)
        inode->i_flags |= S_NOQUOTA;
 
        dqopt->ops[type] = fmt->qf_ops;
-       dqopt->info[type].dqi_format = format_id;
+       dqopt->info[type].dqi_format = fmt;
        if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0)
                goto out_f;
-       sb->dq_op = &dquot_operations;
        set_enable_flags(dqopt, type);
 
        add_dquot_ref(sb, type);
@@ -1288,116 +1277,137 @@ static int quota_on(struct super_block *sb, int type, int format_id, char *path)
        return 0;
 
 out_f:
-       filp_close(f, NULL);
+       if (f)
+               filp_close(f, NULL);
        dqopt->files[type] = NULL;
 out_lock:
        up(&dqopt->dqoff_sem);
+out_fmt:
+       put_quota_format(fmt);
 
        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, int id, caddr_t addr)
+int vfs_quota_sync(struct super_block *sb, int type)
 {
-       int cmds = 0, type = 0, flags = 0;
-       kdev_t dev;
-       struct super_block *sb = NULL;
-       int ret = -EINVAL;
+       return sync_dquots(sb, type);
+}
 
-       lock_kernel();
-       cmds = cmd >> SUBCMDSHIFT;
-       type = cmd & SUBCMDMASK;
+/* Generic routine for getting common part of quota structure */
+static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di)
+{
+       struct mem_dqblk *dm = &dquot->dq_dqb;
 
-       if ((u_int) type >= MAXQUOTAS)
-               goto out;
-       if (id & ~0xFFFF)
-               goto out;
+       di->dqb_bhardlimit = dm->dqb_bhardlimit;
+       di->dqb_bsoftlimit = dm->dqb_bsoftlimit;
+       di->dqb_curspace = dm->dqb_curspace;
+       di->dqb_ihardlimit = dm->dqb_ihardlimit;
+       di->dqb_isoftlimit = dm->dqb_isoftlimit;
+       di->dqb_curinodes = dm->dqb_curinodes;
+       di->dqb_btime = dm->dqb_btime;
+       di->dqb_itime = dm->dqb_itime;
+       di->dqb_valid = QIF_ALL;
+}
 
-       ret = -EPERM;
-       switch (cmds) {
-               case Q_SYNC:
-               case Q_GETSTATS:
-                       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;
-       }
+int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
+{
+       struct dquot *dquot = dqget(sb, id, type);
 
-       ret = -EINVAL;
-       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;
-       }
+       if (!dquot)
+               return -EINVAL;
+       do_get_dqblk(dquot, di);
+       dqput(dquot);
+       return 0;
+}
 
-       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 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(sb, type);
-                       goto out;
-               case Q_GETSTATS:
-                       ret = get_stats(addr);
-                       goto out;
-               case Q_RSQUASH:
-                       ret = quota_root_squash(sb, type, (int *) addr);
-                       goto out;
-               default:
-                       goto out;
+/* Generic routine for setting common part of quota structure */
+static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+{
+       struct mem_dqblk *dm = &dquot->dq_dqb;
+       int check_blim = 0, check_ilim = 0;
+
+       if (di->dqb_valid & QIF_SPACE) {
+               dm->dqb_curspace = di->dqb_curspace;
+               check_blim = 1;
+       }
+       if (di->dqb_valid & QIF_BLIMITS) {
+               dm->dqb_bsoftlimit = di->dqb_bsoftlimit;
+               dm->dqb_bhardlimit = di->dqb_bhardlimit;
+               check_blim = 1;
+       }
+       if (di->dqb_valid & QIF_INODES) {
+               dm->dqb_curinodes = di->dqb_curinodes;
+               check_ilim = 1;
+       }
+       if (di->dqb_valid & QIF_ILIMITS) {
+               dm->dqb_isoftlimit = di->dqb_isoftlimit;
+               dm->dqb_ihardlimit = di->dqb_ihardlimit;
+               check_ilim = 1;
+       }
+       if (di->dqb_valid & QIF_BTIME)
+               dm->dqb_btime = di->dqb_btime;
+       if (di->dqb_valid & QIF_ITIME)
+               dm->dqb_itime = di->dqb_itime;
+
+       if (check_blim) {
+               if (!dm->dqb_bsoftlimit || toqb(dm->dqb_curspace) < dm->dqb_bsoftlimit) {
+                       dm->dqb_btime = 0;
+                       dquot->dq_flags &= ~DQ_BLKS;
+               }
+               else if (!(di->dqb_valid & QIF_BTIME))  /* Set grace only if user hasn't provided his own... */
+                       dm->dqb_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
+       }
+       if (check_ilim) {
+               if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) {
+                       dm->dqb_itime = 0;
+                       dquot->dq_flags &= ~DQ_INODES;
+               }
+               else if (!(di->dqb_valid & QIF_ITIME))  /* Set grace only if user hasn't provided his own... */
+                       dm->dqb_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
        }
+       if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit)
+               dquot->dq_flags &= ~DQ_FAKE;
+       else
+               dquot->dq_flags |= DQ_FAKE;
+       dquot->dq_flags |= DQ_MOD;
+}
 
-       ret = -ENODEV;
-       if (sb && sb_has_quota_enabled(sb, type))
-               ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr);
-out:
-       if (sb)
-               drop_super(sb);
-       unlock_kernel();
-       return ret;
+int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
+{
+       struct dquot *dquot = dqget(sb, id, type);
+
+       if (!dquot)
+               return -EINVAL;
+       do_set_dqblk(dquot, di);
+       dqput(dquot);
+       return 0;
+}
+
+/* Generic routine for getting common part of quota file information */
+int vfs_get_info(struct super_block *sb, int type, struct if_dqinfo *ii)
+{
+       struct mem_dqinfo *mi = sb_dqopt(sb)->info + type;
+
+       ii->dqi_bgrace = mi->dqi_bgrace;
+       ii->dqi_igrace = mi->dqi_igrace;
+       ii->dqi_flags = mi->dqi_flags & DQF_MASK;
+       ii->dqi_valid = IIF_ALL;
+       return 0;
+}
+
+/* Generic routine for setting common part of quota file information */
+int vfs_set_info(struct super_block *sb, int type, struct if_dqinfo *ii)
+{
+       struct mem_dqinfo *mi = sb_dqopt(sb)->info + type;
+
+       if (ii->dqi_valid & IIF_BGRACE)
+               mi->dqi_bgrace = ii->dqi_bgrace;
+       if (ii->dqi_valid & IIF_IGRACE)
+               mi->dqi_igrace = ii->dqi_igrace;
+       if (ii->dqi_valid & IIF_FLAGS)
+               mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK);
+       mark_info_dirty(mi);
+       return 0;
 }
 
 #ifdef CONFIG_PROC_FS
@@ -1413,7 +1423,7 @@ static int read_stats(char *buffer, char **start, off_t offset, int count, int *
        len += sprintf(buffer + len, "Formats");
        lock_kernel();
        for (actqf = quota_formats; actqf; actqf = actqf->qf_next)
-               len += sprintf(buffer + len, " %u", actqf->qf_id);
+               len += sprintf(buffer + len, " %u", actqf->qf_fmt_id);
        unlock_kernel();
        len += sprintf(buffer + len, "\n%u %u %u %u %u %u %u %u\n",
                        dqstats.lookups, dqstats.drops,
@@ -1435,6 +1445,16 @@ static int read_stats(char *buffer, char **start, off_t offset, int count, int *
 }
 #endif
 
+struct quotactl_ops vfs_quotactl_ops {
+       quota_on:       vfs_quota_on,
+       quota_off:      vfs_quota_off,
+       quota_sync:     vfs_quota_sync,
+       get_info:       vfs_get_info,
+       set_info:       vfs_set_info,
+       get_dqblk:      vfs_get_dqblk,
+       set_dqblk:      vfs_set_dqblk
+};
+
 static ctl_table fs_table[] = {
        {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
         0444, NULL, &proc_dointvec},
@@ -1460,3 +1480,7 @@ static int __init dquot_init(void)
        return 0;
 }
 __initcall(dquot_init);
+
+EXPORT_SYMBOL(register_quota_format);
+EXPORT_SYMBOL(unregister_quota_format);
+EXPORT_SYMBOL(dqstats);
diff --git a/fs/quota.c b/fs/quota.c
new file mode 100644 (file)
index 0000000..88d54e8
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * 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 <linux/slab.h>
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+
+int nr_dquots, nr_free_dquots;
+
+/* Check validity of quotactl */
+static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
+{
+       if (type >= MAXQUOTAS)
+               return -EINVAL;
+       /* Is operation supported? */
+       if (!sb->s_qcop)
+               return -ENOSYS;
+
+       switch (cmd) {
+               case Q_GETFMT:
+                       break;
+               case Q_QUOTAON:
+                       if (!sb->s_qcop->quota_on)
+                               return -ENOSYS;
+                       break;
+               case Q_QUOTAOFF:
+                       if (!sb->s_qcop->quota_off)
+                               return -ENOSYS;
+                       break;
+               case Q_SETINFO:
+                       if (!sb->s_qcop->set_info)
+                               return -ENOSYS;
+                       break;
+               case Q_GETINFO:
+                       if (!sb->s_qcop->get_info)
+                               return -ENOSYS;
+                       break;
+               case Q_SETQUOTA:
+                       if (!sb->s_qcop->set_dqblk)
+                               return -ENOSYS;
+                       break;
+               case Q_GETQUOTA:
+                       if (!sb->s_qcop->get_dqblk)
+                               return -ENOSYS;
+               break;
+               case Q_SYNC:
+                       if (!sb->s_qcop->quota_sync)
+                               return -ENOSYS;
+                       break;
+               case Q_XQUOTAON:
+               case Q_XQUOTAOFF:
+               case Q_XQUOTARM:
+                       if (!sb->s_qcop->set_xstate)
+                               return -ENOSYS;
+                       break;
+               case Q_XGETQSTAT:
+                       if (!sb->s_qcop->get_xstate)
+                               return -ENOSYS;
+                       break;
+               case Q_XSETQLIM:
+                       if (!sb->s_qcop->set_xquota)
+                               return -ENOSYS;
+                       break;
+               case Q_XGETQUOTA:
+                       if (!sb->s_qcop->get_xquota)
+                               return -ENOSYS;
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       /* Is quota turned on for commands which need it? */
+       switch (cmd) {
+               case Q_GETFMT:
+               case Q_GETINFO:
+               case Q_QUOTAOFF:
+               case Q_SETINFO:
+               case Q_SETQUOTA:
+               case Q_GETQUOTA:
+                       if (!sb_has_quota_enabled(sb, type))
+                               return -ESRCH;
+       }
+       /* Check privileges */
+       if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) {
+               if (((type == USRQUOTA && current->euid != id) ||
+                    (type == GRPQUOTA && !in_egroup_p(id))) &&
+                   !capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+       }
+       else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT)
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+       return 0;
+}
+
+/* Resolve device pathname to superblock */
+static struct super_block *resolve_dev(const char *path)
+{
+       int ret;
+       mode_t mode;
+       struct nameidata nd;
+       kdev_t dev;
+       struct super_block *sb;
+
+       ret = user_path_walk(path, &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 sb;
+out:
+       return ERR_PTR(ret);
+}
+
+/* Copy parameters and call proper function */
+static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
+{
+       int ret;
+
+       switch (cmd) {
+               case Q_QUOTAON: {
+                       char *pathname;
+
+                       if (IS_ERR(pathname = getname(addr)))
+                               return PTR_ERR(pathname);
+                       ret = sb->s_qcop->quota_on(sb, type, id, pathname);
+                       putname(pathname);
+                       return ret;
+               }
+               case Q_QUOTAOFF:
+                       return sb->s_qcop->quota_off(sb, type);
+
+               case Q_GETFMT: {
+                       __u32 fmt;
+
+                       fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
+                       if (copy_to_user(addr, &fmt, sizeof(fmt)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case Q_GETINFO: {
+                       struct if_dqinfo info;
+
+                       if ((ret = sb->s_qcop->get_info(sb, type, &info)))
+                               return ret;
+                       if (copy_to_user(addr, &info, sizeof(info)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case Q_SETINFO: {
+                       struct if_dqinfo info;
+
+                       if (copy_from_user(&info, addr, sizeof(info)))
+                               return -EFAULT;
+                       return sb->s_qcop->set_info(sb, type, &info);
+               }
+               case Q_GETQUOTA: {
+                       struct if_dqblk idq;
+
+                       if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)))
+                               return ret;
+                       if (copy_to_user(addr, &idq, sizeof(idq)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case Q_SETQUOTA: {
+                       struct if_dqblk idq;
+
+                       if (copy_from_user(&idq, addr, sizeof(idq)))
+                               return -EFAULT;
+                       return sb->s_qcop->set_dqblk(sb, type, id, &idq);
+               }
+               case Q_SYNC:
+                       return sb->s_qcop->quota_sync(sb, type);
+
+               case Q_XQUOTAON:
+               case Q_XQUOTAOFF:
+               case Q_XQUOTARM: {
+                       __u32 flags;
+
+                       if (copy_from_user(&flags, addr, sizeof(flags)))
+                               return -EFAULT;
+                       return sb->s_qcop->set_xstate(sb, flags, cmd);
+               }
+               case Q_XGETQSTAT: {
+                       struct fs_quota_stat fqs;
+               
+                       if ((ret = sb->s_qcop->get_xstate(sb, &fqs)))
+                               return ret;
+                       if (copy_to_user(addr, &fqs, sizeof(fqs)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case Q_XSETQLIM: {
+                       struct fs_disk_quota fdq;
+
+                       if (copy_from_user(&fdq, addr, sizeof(fdq)))
+                               return -EFAULT;
+                      return sb->s_qcop->set_xquota(sb, type, id, &fdq);
+               }
+               case Q_XGETQUOTA: {
+                       struct fs_disk_quota fdq;
+
+                       if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq)))
+                               return ret;
+                       if (copy_to_user(addr, &fdq, sizeof(fdq)))
+                               return -EFAULT;
+                       return 0;
+               }
+               /* We never reach here unless validity check is broken */
+               default:
+                       BUG();
+       }
+       return 0;
+}
+
+/*
+ * 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(unsigned int cmd, const char *special, qid_t id, caddr_t addr)
+{
+       uint cmds, type;
+       struct super_block *sb = NULL;
+       int ret = -EINVAL;
+
+       lock_kernel();
+       cmds = cmd >> SUBCMDSHIFT;
+       type = cmd & SUBCMDMASK;
+
+       if (IS_ERR(sb = resolve_dev(special))) {
+               ret = PTR_ERR(sb);
+               sb = NULL;
+               goto out;
+       }
+       if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0)
+               goto out;
+       ret = do_quotactl(sb, type, cmds, id, addr);
+out:
+       if (sb)
+               drop_super(sb);
+       unlock_kernel();
+       return ret;
+}
index 76d3db53caceef366b6aa074ed91ec0c4d12dd57..269eaeb3cba5c2d8dc44ef1420ed3ad261a43425 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/acct.h>
 #include <linux/blkdev.h>
+#include <linux/quotaops.h>
 #include <asm/uaccess.h>
 
 void get_filesystem(struct file_system_type *fs);
@@ -62,6 +63,8 @@ static struct super_block *alloc_super(void)
                sema_init(&s->s_dquot.dqio_sem, 1);
                sema_init(&s->s_dquot.dqoff_sem, 1);
                s->s_maxbytes = MAX_NON_LFS;
+               s->dq_op = sb_dquot_ops;
+               s->s_qcop = sb_quotactl_ops;
        }
        return s;
 }
index f50388ea30dc7fb5c3a5e76e13910ad13a0c79da..f30905c9a4f16e39d960f16597b7a9ea50390a83 100644 (file)
@@ -626,7 +626,7 @@ struct quota_info {
        struct semaphore dqoff_sem;             /* serialize quota_off() and quota_on() on device */
        struct file *files[MAXQUOTAS];          /* fp's to quotafiles */
        struct mem_dqinfo info[MAXQUOTAS];      /* Information for each quota type */
-       struct quota_format_ops *ops[MAXQUOTAS];        /* Operations for each format */
+       struct quota_format_ops *ops[MAXQUOTAS];        /* Operations for each type */
 };
 
 /*
@@ -659,6 +659,7 @@ struct super_block {
        struct file_system_type *s_type;
        struct super_operations *s_op;
        struct dquot_operations *dq_op;
+       struct quotactl_ops     *s_qcop;
        struct export_operations *s_export_op;
        unsigned long           s_flags;
        unsigned long           s_magic;
@@ -878,16 +879,6 @@ static inline void mark_inode_dirty_sync(struct inode *inode)
        __mark_inode_dirty(inode, I_DIRTY_SYNC);
 }
 
-struct dquot_operations {
-       void (*initialize) (struct inode *, short);
-       void (*drop) (struct inode *);
-       int (*alloc_space) (struct inode *, qsize_t, int);
-       int (*alloc_inode) (const struct inode *, unsigned long);
-       void (*free_space) (struct inode *, qsize_t);
-       void (*free_inode) (const struct inode *, unsigned long);
-       int (*transfer) (struct inode *, struct iattr *);
-};
-
 
 /**
  * &export_operations - for nfsd to communicate with file systems
index 7e481591efc4c5b69d6d474b93c59450c6d3569d..49ceac92bc2961694dd5fc3900a50312f6ee065e 100644 (file)
@@ -70,9 +70,6 @@ typedef __u64 qsize_t;          /* Type in which we store sizes */
        "undefined", \
 };
 
-#define QUOTAFILENAME "quota"
-#define QUOTAGROUP "staff"
-
 /*
  * Command definitions for the 'quotactl' system call.
  * The commands are broken into a main command defined below
@@ -83,7 +80,61 @@ typedef __u64 qsize_t;          /* Type in which we store sizes */
 #define SUBCMDSHIFT 8
 #define QCMD(cmd, type)  (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
 
-#define Q_SYNC     0x0600      /* sync disk copy of a filesystems quotas */
+#define Q_SYNC     0x800001    /* sync disk copy of a filesystems quotas */
+#define Q_QUOTAON  0x800002    /* turn quotas on */
+#define Q_QUOTAOFF 0x800003    /* turn quotas off */
+#define Q_GETFMT   0x800004    /* get quota format used on given filesystem */
+#define Q_GETINFO  0x800005    /* get information about quota files */
+#define Q_SETINFO  0x800006    /* set information about quota files */
+#define Q_GETQUOTA 0x800007    /* get user quota structure */
+#define Q_SETQUOTA 0x800008    /* set user quota structure */
+
+/*
+ * Quota structure used for communication with userspace via quotactl
+ * Following flags are used to specify which fields are valid
+ */
+#define QIF_BLIMITS    1
+#define QIF_SPACE      2
+#define QIF_ILIMITS    4
+#define QIF_INODES     8
+#define QIF_BTIME      16
+#define QIF_ITIME      32
+#define QIF_LIMITS     (QIF_BLIMITS | QIF_ILIMITS)
+#define QIF_USAGE      (QIF_SPACE | QIF_INODES)
+#define QIF_TIMES      (QIF_BTIME | QIF_ITIME)
+#define QIF_ALL                (QIF_LIMITS | QIF_USAGE | QIF_TIMES)
+
+struct if_dqblk {
+       __u64 dqb_bhardlimit;
+       __u64 dqb_bsoftlimit;
+       __u64 dqb_curspace;
+       __u64 dqb_ihardlimit;
+       __u64 dqb_isoftlimit;
+       __u64 dqb_curinodes;
+       __u64 dqb_btime;
+       __u64 dqb_itime;
+       __u32 dqb_valid;
+};
+
+/*
+ * Structure used for setting quota information about file via quotactl
+ * Following flags are used to specify which fields are valid
+ */
+#define IIF_BGRACE     1
+#define IIF_IGRACE     2
+#define IIF_FLAGS      4
+#define IIF_ALL                (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS)
+
+struct if_dqinfo {
+       __u64 dqi_bgrace;
+       __u64 dqi_igrace;
+       __u32 dqi_flags;
+       __u32 dqi_valid;
+};
+
+#ifdef __KERNEL__
+
+#include <linux/xqm.h>
 
 /*
  * Data for one user/group kept in memory
@@ -105,7 +156,7 @@ struct mem_dqblk {
 struct quota_format_type;
 
 struct mem_dqinfo {
-       struct quota_format_type * dqi_format;
+       struct quota_format_type *dqi_format;
        int dqi_flags;
        unsigned int dqi_bgrace;
        unsigned int dqi_igrace;
@@ -113,8 +164,6 @@ struct mem_dqinfo {
        } u;
 };
 
-#ifdef __KERNEL__
-
 #define DQF_MASK 0xffff                /* Mask for format specific flags */
 #define DQF_INFO_DIRTY 0x10000  /* Is info dirty? */
 
@@ -127,24 +176,6 @@ extern inline void mark_info_dirty(struct mem_dqinfo *info)
 
 #define sb_dqopt(sb) (&(sb)->s_dquot)
 
-#endif  /* __KERNEL__ */
-
-/*
- * Shorthand notation.
- */
-#define        dq_bhardlimit   dq_dqb.dqb_bhardlimit
-#define        dq_bsoftlimit   dq_dqb.dqb_bsoftlimit
-#define        dq_curspace     dq_dqb.dqb_curspace
-#define        dq_ihardlimit   dq_dqb.dqb_ihardlimit
-#define        dq_isoftlimit   dq_dqb.dqb_isoftlimit
-#define        dq_curinodes    dq_dqb.dqb_curinodes
-#define        dq_btime        dq_dqb.dqb_btime
-#define        dq_itime        dq_dqb.dqb_itime
-
-#define dqoff(UID)      ((loff_t)((UID) * sizeof (struct dqblk)))
-
-#ifdef __KERNEL__
-
 extern int nr_dquots, nr_free_dquots;
 
 struct dqstats {
@@ -203,25 +234,70 @@ extern inline void mark_dquot_dirty(struct dquot *dquot)
 /* Operations which must be implemented by each quota format */
 struct quota_format_ops {
        int (*check_quota_file)(struct super_block *sb, int type);      /* Detect whether file is in our format */
-       int (*read_file_info)(struct super_block *sb, int type);        /* Read main info about file */
+       int (*read_file_info)(struct super_block *sb, int type);        /* Read main info about file - called on quotaon() */
        int (*write_file_info)(struct super_block *sb, int type);       /* Write main info about file */
        int (*free_file_info)(struct super_block *sb, int type);        /* Called on quotaoff() */
        int (*read_dqblk)(struct dquot *dquot);         /* Read structure for one user */
        int (*commit_dqblk)(struct dquot *dquot);       /* Write (or delete) structure for one user */
 };
 
+/* Operations working with dquots */
+struct dquot_operations {
+       void (*initialize) (struct inode *, short);
+       void (*drop) (struct inode *);
+       int (*alloc_space) (struct inode *, qsize_t, int);
+       int (*alloc_inode) (const struct inode *, unsigned long);
+       void (*free_space) (struct inode *, qsize_t);
+       void (*free_inode) (const struct inode *, unsigned long);
+       int (*transfer) (struct inode *, struct iattr *);
+};
+
+/* Operations handling requests from userspace */
+struct quotactl_ops {
+       int (*quota_on)(struct super_block *, int, int, char *);
+       int (*quota_off)(struct super_block *, int);
+       int (*quota_sync)(struct super_block *, int);
+       int (*get_info)(struct super_block *, int, struct if_dqinfo *);
+       int (*set_info)(struct super_block *, int, struct if_dqinfo *);
+       int (*get_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *);
+       int (*set_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *);
+       int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
+       int (*set_xstate)(struct super_block *, unsigned int, int);
+       int (*get_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+       int (*set_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+};
+
 struct quota_format_type {
        int qf_fmt_id;  /* Quota format id */
        struct quota_format_ops *qf_ops;        /* Operations of format */
+       struct module *qf_owner;                /* Module implementing quota format */
        struct quota_format_type *qf_next;
 };
 
+static inline int is_enabled(struct quota_info *dqopt, int type)
+{
+       switch (type) {
+               case USRQUOTA:
+                       return dqopt->flags & DQUOT_USR_ENABLED;
+               case GRPQUOTA:
+                       return dqopt->flags & DQUOT_GRP_ENABLED;
+       }
+       return 0;
+}
+
+#define sb_any_quota_enabled(sb) (is_enabled(sb_dqopt(sb), USRQUOTA) | is_enabled(sb_dqopt(sb), GRPQUOTA))
+
+#define sb_has_quota_enabled(sb, type) (is_enabled(sb_dqopt(sb), type))
+
+int register_quota_format(struct quota_format_type *fmt);
+void unregister_quota_format(struct quota_format_type *fmt);
+
 #else
 
 # /* nodep */ include <sys/cdefs.h>
 
 __BEGIN_DECLS
-long quotactl __P ((int, const char *, int, caddr_t));
+long quotactl __P ((unsigned int, const char *, int, caddr_t));
 __END_DECLS
 
 #endif /* __KERNEL__ */
index b5da5ff5bb9abdc649d2bfd07d8b0410c2084fcb..0cd58a4fa275c754b42d1ba454c604364408cbca 100644 (file)
 /*
  * declaration of quota_function calls in kernel.
  */
+extern int sync_dquots(kdev_t dev, short type);
+
 extern void dquot_initialize(struct inode *inode, short type);
 extern void dquot_drop(struct inode *inode);
-extern int  quota_off(struct super_block *sb, short type);
-extern int  sync_dquots(struct super_block *sb, short type);
 
 extern int  dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc);
 extern int  dquot_alloc_inode(const struct inode *inode, unsigned long number);
@@ -36,7 +36,11 @@ extern int  dquot_transfer(struct inode *inode, struct iattr *iattr);
 /*
  * Operations supported for diskquotas.
  */
-#define sb_any_quota_enabled(sb) ((sb)->s_dquot.flags & (DQUOT_USR_ENABLED | DQUOT_GRP_ENABLED))
+extern struct dquot_operations dquot_operations;
+extern struct quotactl_ops vfs_quotactl_ops;
+
+#define sb_dquot_ops (&dquot_operations)
+#define sb_quotactl_ops (&vfs_quotactl_ops)
 
 static __inline__ void DQUOT_INIT(struct inode *inode)
 {
@@ -160,13 +164,25 @@ static __inline__ int DQUOT_TRANSFER(struct inode *inode, struct iattr *iattr)
 }
 
 #define DQUOT_SYNC(sb) sync_dquots(sb, -1)
-#define DQUOT_OFF(sb)  quota_off(sb, -1)
+
+static __inline__ int DQUOT_OFF(struct super_block *sb)
+{
+       int ret = -ENOSYS;
+
+       lock_kernel();
+       if (sb->s_qcop && sb->s_qcop->quota_off)
+               ret = sb->s_qcop->quota_off(sb, -1);
+       unlock_kernel();
+       return ret;
+}
 
 #else
 
 /*
  * NO-OP when quota not configured.
  */
+#define sb_dquot_ops                           (NULL)
+#define sb_quotactl_ops                                (NULL)
 #define DQUOT_INIT(inode)                      do { } while(0)
 #define DQUOT_DROP(inode)                      do { } while(0)
 #define DQUOT_ALLOC_INODE(inode)               (0)
diff --git a/include/linux/xqm.h b/include/linux/xqm.h
new file mode 100644 (file)
index 0000000..d077bc1
--- /dev/null
@@ -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 */