Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / fs / quota.c
index cd9dfd5..56ff735 100644 (file)
 #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)
@@ -81,11 +84,11 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid
        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;
@@ -120,6 +123,10 @@ static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t i
                        if (!sb->s_qcop->get_xquota)
                                return -ENOSYS;
                        break;
+               case Q_XQUOTASYNC:
+                       if (!sb->s_qcop->quota_sync)
+                               return -ENOSYS;
+                       break;
                default:
                        return -EINVAL;
        }
@@ -128,10 +135,10 @@ static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t i
        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;
        }
 
@@ -151,36 +158,6 @@ static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t
        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;
@@ -195,11 +172,11 @@ static void quota_sync_sb(struct super_block *sb, int type)
        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)
@@ -208,12 +185,12 @@ static void quota_sync_sb(struct super_block *sb, int 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]);
                }
        }
@@ -221,17 +198,35 @@ static void quota_sync_sb(struct super_block *sb, int type)
 
 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 */
@@ -336,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();
@@ -343,8 +340,41 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void
        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
 
 /*
@@ -372,11 +402,16 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t
                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))