X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fquota.c;h=56ff735bfe6c5da9eb700d14d9508d5d19c451c9;hb=3967a72a825e44bff5d10f516e90b6f59f59e599;hp=3dd9be6b2377d6d2ab48a3c76dd290b3ef76fafd;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/fs/quota.c b/fs/quota.c index 3dd9be6b2..56ff735bf 100644 --- a/fs/quota.c +++ b/fs/quota.c @@ -13,9 +13,16 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include -/* Check validity of quotactl */ -static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +/* Check validity of generic quotactl commands */ +static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) { if (type >= MAXQUOTAS) return -EINVAL; @@ -56,6 +63,48 @@ static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t if (sb && !sb->s_qcop->quota_sync) 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: + /* This is just informative test so we are satisfied without a lock */ + if (!sb_has_quota_enabled(sb, type)) + return -ESRCH; + } + + /* Check privileges */ + if (cmd == Q_GETQUOTA) { + if (((type == USRQUOTA && current->euid != id) || + (type == GRPQUOTA && !in_egroup_p(id))) && + !vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) + return -EPERM; + } + else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO) + if (!vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) + return -EPERM; + + return 0; +} + +/* Check validity of XFS Quota Manager commands */ +static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +{ + if (type >= XQM_MAXQUOTAS) + return -EINVAL; + if (!sb) + return -ENODEV; + if (!sb->s_qcop) + return -ENOSYS; + + switch (cmd) { case Q_XQUOTAON: case Q_XQUOTAOFF: case Q_XQUOTARM: @@ -74,46 +123,92 @@ static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t if (!sb->s_qcop->get_xquota) return -ENOSYS; break; + case Q_XQUOTASYNC: + if (!sb->s_qcop->quota_sync) + 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: - /* This is just informative test so we are satisfied without a lock */ - 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)) + if (cmd == Q_XGETQUOTA) { + if (((type == XQM_USRQUOTA && current->euid != id) || + (type == XQM_GRPQUOTA && !in_egroup_p(id))) && + !vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) return -EPERM; - } - else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT) - if (!capable(CAP_SYS_ADMIN)) + } else if (cmd != Q_XGETQSTAT && cmd != Q_XQUOTASYNC) { + if (!vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) return -EPERM; + } - return security_quotactl (cmd, type, id, sb); + return 0; +} + +static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +{ + int error; + + if (XQM_COMMAND(cmd)) + error = xqm_quotactl_valid(sb, type, cmd, id); + else + error = generic_quotactl_valid(sb, type, cmd, id); + if (!error) + error = security_quotactl(cmd, type, id, sb); + return error; +} + +static void quota_sync_sb(struct super_block *sb, int type) +{ + int cnt; + struct inode *discard[MAXQUOTAS]; + + sb->s_qcop->quota_sync(sb, type); + /* This is not very clever (and fast) but currently I don't know about + * any other simple way of getting quota data to disk and we must get + * them there for userspace to be visible... */ + if (sb->s_op->sync_fs) + sb->s_op->sync_fs(sb, 1); + sync_blockdev(sb->s_bdev); + + /* Now when everything is written we can discard the pagecache so + * that userspace sees the changes. We need i_mutex and so we could + * not do it inside dqonoff_mutex. Moreover we need to be carefull + * about races with quotaoff() (that is the reason why we have own + * reference to inode). */ + mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + discard[cnt] = NULL; + if (type != -1 && cnt != type) + continue; + if (!sb_has_quota_enabled(sb, cnt)) + continue; + discard[cnt] = igrab(sb_dqopt(sb)->files[cnt]); + } + mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (discard[cnt]) { + mutex_lock(&discard[cnt]->i_mutex); + truncate_inode_pages(&discard[cnt]->i_data, 0); + mutex_unlock(&discard[cnt]->i_mutex); + iput(discard[cnt]); + } + } } -static struct super_block *get_super_to_sync(int type) +void sync_dquots(struct super_block *sb, int type) { - struct list_head *head; int cnt, dirty; -restart: - spin_lock(&sb_lock); - list_for_each(head, &super_blocks) { - struct super_block *sb = list_entry(head, struct super_block, s_list); + if (sb) { + if (sb->s_qcop->quota_sync) + quota_sync_sb(sb, type); + return; + } + spin_lock(&sb_lock); +restart: + list_for_each_entry(sb, &super_blocks, s_list) { /* This test just improves performance so it needn't be reliable... */ for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) @@ -124,29 +219,14 @@ restart: sb->s_count++; spin_unlock(&sb_lock); down_read(&sb->s_umount); - if (!sb->s_root) { - drop_super(sb); + if (sb->s_root && sb->s_qcop->quota_sync) + quota_sync_sb(sb, type); + up_read(&sb->s_umount); + spin_lock(&sb_lock); + if (__put_super_and_need_restart(sb)) goto restart; - } - return sb; } spin_unlock(&sb_lock); - return NULL; -} - -void sync_dquots(struct super_block *sb, int type) -{ - if (sb) { - if (sb->s_qcop->quota_sync) - sb->s_qcop->quota_sync(sb, type); - } - else { - while ((sb = get_super_to_sync(type)) != 0) { - if (sb->s_qcop->quota_sync) - sb->s_qcop->quota_sync(sb, type); - drop_super(sb); - } - } } /* Copy parameters and call proper function */ @@ -251,6 +331,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void return -EFAULT; return 0; } + case Q_XQUOTASYNC: + return sb->s_qcop->quota_sync(sb, type); /* We never reach here unless validity check is broken */ default: BUG(); @@ -258,6 +340,43 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void return 0; } +#if defined(CONFIG_BLK_DEV_VROOT) || defined(CONFIG_BLK_DEV_VROOT_MODULE) + +#include +#include + +static vroot_grb_func *vroot_get_real_bdev = NULL; + +static spinlock_t vroot_grb_lock = SPIN_LOCK_UNLOCKED; + +int register_vroot_grb(vroot_grb_func *func) { + int ret = -EBUSY; + + spin_lock(&vroot_grb_lock); + if (!vroot_get_real_bdev) { + vroot_get_real_bdev = func; + ret = 0; + } + spin_unlock(&vroot_grb_lock); + return ret; +} +EXPORT_SYMBOL(register_vroot_grb); + +int unregister_vroot_grb(vroot_grb_func *func) { + int ret = -EINVAL; + + spin_lock(&vroot_grb_lock); + if (vroot_get_real_bdev) { + vroot_get_real_bdev = NULL; + ret = 0; + } + spin_unlock(&vroot_grb_lock); + return ret; +} +EXPORT_SYMBOL(unregister_vroot_grb); + +#endif + /* * This is the system call interface. This communicates with * the user-level programs. Currently this only supports diskquota @@ -283,6 +402,23 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t putname(tmp); if (IS_ERR(bdev)) return PTR_ERR(bdev); +#if defined(CONFIG_BLK_DEV_VROOT) || defined(CONFIG_BLK_DEV_VROOT_MODULE) + if (bdev && bdev->bd_inode && + imajor(bdev->bd_inode) == VROOT_MAJOR) { + struct block_device *bdnew = (void *)-EINVAL; + + if (vroot_get_real_bdev) + bdnew = vroot_get_real_bdev(bdev); + else + vxdprintk(VXD_CBIT(misc, 0), + "vroot_get_real_bdev not set"); + + bdput(bdev); + if (IS_ERR(bdnew)) + return PTR_ERR(bdnew); + bdev = bdnew; + } +#endif sb = get_super(bdev); bdput(bdev); if (!sb)