diff options
| -rw-r--r-- | arch/ia64/ia32/ia32_entry.S | 2 | ||||
| -rw-r--r-- | arch/ia64/ia32/sys_ia32.c | 54 | ||||
| -rw-r--r-- | arch/s390x/kernel/linux32.c | 58 | ||||
| -rw-r--r-- | arch/s390x/kernel/wrapper32.S | 2 | ||||
| -rw-r--r-- | arch/sparc64/kernel/sys_sparc32.c | 56 | ||||
| -rw-r--r-- | arch/sparc64/kernel/systbls.S | 4 | ||||
| -rw-r--r-- | fs/Makefile | 2 | ||||
| -rw-r--r-- | fs/dquot.c | 344 | ||||
| -rw-r--r-- | fs/quota.c | 263 | ||||
| -rw-r--r-- | fs/super.c | 3 | ||||
| -rw-r--r-- | include/linux/fs.h | 13 | ||||
| -rw-r--r-- | include/linux/quota.h | 130 | ||||
| -rw-r--r-- | include/linux/quotaops.h | 24 | ||||
| -rw-r--r-- | include/linux/xqm.h | 159 |
14 files changed, 739 insertions, 375 deletions
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index f3e7e950b7ac..f9595d3f43ed 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -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 */ diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index 0bcd16ac271e..c3852b487a11 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -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) { diff --git a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c index a125f2d41043..e06f1958dd10 100644 --- a/arch/s390x/kernel/linux32.c +++ b/arch/s390x/kernel/linux32.c @@ -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; diff --git a/arch/s390x/kernel/wrapper32.S b/arch/s390x/kernel/wrapper32.S index a11ee19b21ff..8a66558332b1 100644 --- a/arch/s390x/kernel/wrapper32.S +++ b/arch/s390x/kernel/wrapper32.S @@ -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: diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 0e4720e33966..224387833d54 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -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; diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index b7b5414167bd..6138ce2fca94 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -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 diff --git a/fs/Makefile b/fs/Makefile index 83769de6e2e4..e843c709297e 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -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),) diff --git a/fs/dquot.c b/fs/dquot.c index 1503708a4657..b6125801dd94 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -62,12 +62,11 @@ #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 index 000000000000..88d54e8ade7b --- /dev/null +++ b/fs/quota.c @@ -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; +} diff --git a/fs/super.c b/fs/super.c index 76d3db53cace..269eaeb3cba5 100644 --- a/fs/super.c +++ b/fs/super.c @@ -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; } diff --git a/include/linux/fs.h b/include/linux/fs.h index f50388ea30dc..f30905c9a4f1 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -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 diff --git a/include/linux/quota.h b/include/linux/quota.h index 7e481591efc4..49ceac92bc29 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -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__ */ diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index b5da5ff5bb9a..0cd58a4fa275 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -20,10 +20,10 @@ /* * 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 index 000000000000..d077bc18a424 --- /dev/null +++ b/include/linux/xqm.h @@ -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 */ |
