#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/buffer_head.h>
+#include <linux/capability.h>
+#include <linux/quotaops.h>
#include <linux/major.h>
#include <linux/blkdev.h>
+#include <linux/vserver/debug.h>
/* Check validity of generic quotactl commands */
static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
if (cmd == Q_GETQUOTA) {
if (((type == USRQUOTA && current->euid != id) ||
(type == GRPQUOTA && !in_egroup_p(id))) &&
- !capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_QUOTA_CTL))
+ !vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL))
return -EPERM;
}
else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO)
- if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_QUOTA_CTL))
+ if (!vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL))
return -EPERM;
return 0;
if (!sb->s_qcop->get_xquota)
return -ENOSYS;
break;
+ case Q_XQUOTASYNC:
+ if (!sb->s_qcop->quota_sync)
+ return -ENOSYS;
+ break;
default:
return -EINVAL;
}
if (cmd == Q_XGETQUOTA) {
if (((type == XQM_USRQUOTA && current->euid != id) ||
(type == XQM_GRPQUOTA && !in_egroup_p(id))) &&
- !capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_QUOTA_CTL))
+ !vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL))
return -EPERM;
- } else if (cmd != Q_XGETQSTAT) {
- if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_QUOTA_CTL))
+ } else if (cmd != Q_XGETQSTAT && cmd != Q_XQUOTASYNC) {
+ if (!vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL))
return -EPERM;
}
return error;
}
-static struct super_block *get_super_to_sync(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);
-
- /* 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)
- && info_any_dirty(&sb_dqopt(sb)->info[cnt]))
- dirty = 1;
- if (!dirty)
- continue;
- sb->s_count++;
- spin_unlock(&sb_lock);
- down_read(&sb->s_umount);
- if (!sb->s_root) {
- drop_super(sb);
- goto restart;
- }
- return sb;
- }
- spin_unlock(&sb_lock);
- return NULL;
-}
-
static void quota_sync_sb(struct super_block *sb, int type)
{
int cnt;
sync_blockdev(sb->s_bdev);
/* Now when everything is written we can discard the pagecache so
- * that userspace sees the changes. We need i_sem and so we could
- * not do it inside dqonoff_sem. Moreover we need to be carefull
+ * 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). */
- down(&sb_dqopt(sb)->dqonoff_sem);
+ mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
discard[cnt] = NULL;
if (type != -1 && cnt != type)
continue;
discard[cnt] = igrab(sb_dqopt(sb)->files[cnt]);
}
- up(&sb_dqopt(sb)->dqonoff_sem);
+ mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (discard[cnt]) {
- down(&discard[cnt]->i_sem);
+ mutex_lock(&discard[cnt]->i_mutex);
truncate_inode_pages(&discard[cnt]->i_data, 0);
- up(&discard[cnt]->i_sem);
+ mutex_unlock(&discard[cnt]->i_mutex);
iput(discard[cnt]);
}
}
void sync_dquots(struct super_block *sb, int type)
{
+ int cnt, dirty;
+
if (sb) {
if (sb->s_qcop->quota_sync)
quota_sync_sb(sb, type);
+ return;
}
- else {
- while ((sb = get_super_to_sync(type)) != NULL) {
- if (sb->s_qcop->quota_sync)
- quota_sync_sb(sb, type);
- drop_super(sb);
- }
+
+ 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)
+ && info_any_dirty(&sb_dqopt(sb)->info[cnt]))
+ dirty = 1;
+ if (!dirty)
+ continue;
+ sb->s_count++;
+ spin_unlock(&sb_lock);
+ down_read(&sb->s_umount);
+ 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;
}
+ spin_unlock(&sb_lock);
}
/* Copy parameters and call proper function */
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();
return 0;
}
-#ifdef CONFIG_BLK_DEV_VROOT
-extern struct block_device *vroot_get_real_bdev(struct block_device *);
+#if defined(CONFIG_BLK_DEV_VROOT) || defined(CONFIG_BLK_DEV_VROOT_MODULE)
+
+#include <linux/vroot.h>
+#include <linux/kallsyms.h>
+
+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
/*
putname(tmp);
if (IS_ERR(bdev))
return PTR_ERR(bdev);
-#ifdef CONFIG_BLK_DEV_VROOT
+#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 =
- vroot_get_real_bdev(bdev);
+ 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))