--- linux-2.6.12.2/drivers/block/Kconfig	2005-06-22 02:38:02 +0200
+++ linux-2.6.12.2-vs2.0-rc6.1/drivers/block/Kconfig	2005-07-02 22:38:30 +0200
@@ -315,6 +315,12 @@ config BLK_DEV_CRYPTOLOOP
 	  instead, which can be configured to be on-disk compatible with the
 	  cryptoloop device.
 
+config BLK_DEV_VROOT
+	tristate "Virtual Root device support"
+	---help---
+	  Saying Y here will allow you to use quota/fs ioctls on a shared
+	  partition within a virtual server without compromising security.
+
 config BLK_DEV_NBD
 	tristate "Network block device support"
 	depends on NET
--- linux-2.6.12.2/drivers/block/Makefile	2004-12-25 01:54:52 +0100
+++ linux-2.6.12.2-vs2.0-rc6.1/drivers/block/Makefile	2005-07-02 22:38:30 +0200
@@ -44,4 +44,5 @@ obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryp
 obj-$(CONFIG_VIODASD)		+= viodasd.o
 obj-$(CONFIG_BLK_DEV_SX8)	+= sx8.o
 obj-$(CONFIG_BLK_DEV_UB)	+= ub.o
+obj-$(CONFIG_BLK_DEV_VROOT)	+= vroot.o
 
--- linux-2.6.12.2/drivers/block/vroot.c	1970-01-01 01:00:00 +0100
+++ linux-2.6.12.2-vs2.0-rc6.1/drivers/block/vroot.c	2005-07-02 22:38:30 +0200
@@ -0,0 +1,266 @@
+/*
+ *  linux/drivers/block/vroot.c
+ *
+ *  written by Herbert P�tzl, 9/11/2002
+ *  ported to 2.6.10 by Herbert P�tzl, 30/12/2004
+ *
+ *  based on the loop.c code by Theodore Ts'o.
+ *
+ * Copyright (C) 2002-2005 by Herbert P�tzl.
+ * Redistribution of this file is permitted under the
+ * GNU General Public License.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/file.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <linux/vroot.h>
+
+
+static int max_vroot = 8;
+
+static struct vroot_device *vroot_dev;
+static struct gendisk **disks;
+
+
+static int vroot_set_dev(
+	struct vroot_device *vr,
+	struct file *vr_file,
+	struct block_device *bdev,
+	unsigned int arg)
+{
+	struct block_device *real_bdev;
+	struct file *file;
+	struct inode *inode;
+	int error;
+
+	error = -EBUSY;
+	if (vr->vr_state != Vr_unbound)
+		goto out;
+
+	error = -EBADF;
+	file = fget(arg);
+	if (!file)
+		goto out;
+
+	error = -EINVAL;
+	inode = file->f_dentry->d_inode;
+
+
+	if (S_ISBLK(inode->i_mode)) {
+		real_bdev = inode->i_bdev;
+		vr->vr_device = real_bdev;
+		__iget(real_bdev->bd_inode);
+	} else
+		goto out_fput;
+
+	printk(KERN_INFO "vroot[%d]_set_dev: dev=%p[%d,%d]\n",
+		vr->vr_number, real_bdev,
+		imajor(real_bdev->bd_inode), iminor(real_bdev->bd_inode));
+
+	vr->vr_state = Vr_bound;
+	error = 0;
+
+ out_fput:
+	fput(file);
+ out:
+	return error;
+}
+
+static int vroot_clr_dev(
+	struct vroot_device *vr,
+	struct file *vr_file,
+	struct block_device *bdev)
+{
+	struct block_device *real_bdev;
+
+	if (vr->vr_state != Vr_bound)
+		return -ENXIO;
+	if (vr->vr_refcnt > 1)	/* we needed one fd for the ioctl */
+		return -EBUSY;
+
+	real_bdev = vr->vr_device;
+
+	printk(KERN_INFO "vroot[%d]_clr_dev: dev=%p[%d,%d]\n",
+		vr->vr_number, real_bdev,
+		imajor(real_bdev->bd_inode), iminor(real_bdev->bd_inode));
+
+	bdput(real_bdev);
+	vr->vr_state = Vr_unbound;
+	vr->vr_device = NULL;
+	return 0;
+}
+
+
+static int vr_ioctl(struct inode * inode, struct file * file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct vroot_device *vr = inode->i_bdev->bd_disk->private_data;
+	int err;
+
+	down(&vr->vr_ctl_mutex);
+	switch (cmd) {
+	case VROOT_SET_DEV:
+		err = vroot_set_dev(vr, file, inode->i_bdev, arg);
+		break;
+	case VROOT_CLR_DEV:
+		err = vroot_clr_dev(vr, file, inode->i_bdev);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	up(&vr->vr_ctl_mutex);
+	return err;
+}
+
+static int vr_open(struct inode *inode, struct file *file)
+{
+	struct vroot_device *vr = inode->i_bdev->bd_disk->private_data;
+
+	down(&vr->vr_ctl_mutex);
+	vr->vr_refcnt++;
+	up(&vr->vr_ctl_mutex);
+	return 0;
+}
+
+static int vr_release(struct inode *inode, struct file *file)
+{
+	struct vroot_device *vr = inode->i_bdev->bd_disk->private_data;
+
+	down(&vr->vr_ctl_mutex);
+	--vr->vr_refcnt;
+	up(&vr->vr_ctl_mutex);
+	return 0;
+}
+
+static struct block_device_operations vr_fops = {
+	.owner =	THIS_MODULE,
+	.open =		vr_open,
+	.release =	vr_release,
+	.ioctl =	vr_ioctl,
+};
+
+struct block_device *vroot_get_real_bdev(struct block_device *bdev)
+{
+	struct inode *inode = bdev->bd_inode;
+	struct vroot_device *vr;
+	struct block_device *real_bdev;
+	int minor = iminor(inode);
+
+	vr = &vroot_dev[minor];
+	real_bdev = vr->vr_device;
+
+	printk(KERN_INFO "vroot[%d]_get_real_bdev: dev=%p[%p,%d,%d]\n",
+		vr->vr_number, real_bdev, real_bdev->bd_inode,
+		imajor(real_bdev->bd_inode), iminor(real_bdev->bd_inode));
+
+	if (vr->vr_state != Vr_bound)
+		return ERR_PTR(-ENXIO);
+
+	__iget(real_bdev->bd_inode);
+	return real_bdev;
+}
+
+/*
+ * And now the modules code and kernel interface.
+ */
+
+module_param(max_vroot, int, 0);
+
+MODULE_PARM_DESC(max_vroot, "Maximum number of vroot devices (1-256)");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(VROOT_MAJOR);
+
+MODULE_AUTHOR ("Herbert P�tzl");
+MODULE_DESCRIPTION ("Virtual Root Device Mapper");
+
+
+int __init vroot_init(void)
+{
+	int	i;
+
+	if (max_vroot < 1 || max_vroot > 256) {
+		max_vroot = MAX_VROOT_DEFAULT;
+		printk(KERN_WARNING "vroot: invalid max_vroot "
+			"(must be between 1 and 256), "
+			"using default (%d)\n", max_vroot);
+	}
+
+	if (register_blkdev(VROOT_MAJOR, "vroot"))
+		return -EIO;
+
+	vroot_dev = kmalloc(max_vroot * sizeof(struct vroot_device), GFP_KERNEL);
+	if (!vroot_dev)
+		goto out_mem1;
+	memset(vroot_dev, 0, max_vroot * sizeof(struct vroot_device));
+
+	disks = kmalloc(max_vroot * sizeof(struct gendisk *), GFP_KERNEL);
+	if (!disks)
+		goto out_mem2;
+
+	for (i = 0; i < max_vroot; i++) {
+		disks[i] = alloc_disk(1);
+		if (!disks[i])
+			goto out_mem3;
+	}
+
+	devfs_mk_dir("vroot");
+
+	for (i = 0; i < max_vroot; i++) {
+		struct vroot_device *vr = &vroot_dev[i];
+		struct gendisk *disk = disks[i];
+
+		memset(vr, 0, sizeof(*vr));
+		init_MUTEX(&vr->vr_ctl_mutex);
+		vr->vr_number = i;
+		disk->major = VROOT_MAJOR;
+		disk->first_minor = i;
+		disk->fops = &vr_fops;
+		sprintf(disk->disk_name, "vroot%d", i);
+		sprintf(disk->devfs_name, "vroot/%d", i);
+		disk->private_data = vr;
+	}
+
+	for (i = 0; i < max_vroot; i++)
+		add_disk(disks[i]);
+	printk(KERN_INFO "vroot: loaded (max %d devices)\n", max_vroot);
+	return 0;
+
+out_mem3:
+	while (i--)
+		put_disk(disks[i]);
+	kfree(disks);
+out_mem2:
+	kfree(vroot_dev);
+out_mem1:
+	unregister_blkdev(VROOT_MAJOR, "vroot");
+	printk(KERN_ERR "vroot: ran out of memory\n");
+	return -ENOMEM;
+}
+
+void vroot_exit(void)
+{
+	int i;
+
+	for (i = 0; i < max_vroot; i++) {
+		del_gendisk(disks[i]);
+		put_disk(disks[i]);
+	}
+	devfs_remove("vroot");
+	if (unregister_blkdev(VROOT_MAJOR, "vroot"))
+		printk(KERN_WARNING "vroot: cannot unregister blkdev\n");
+
+	kfree(disks);
+	kfree(vroot_dev);
+}
+
+module_init(vroot_init);
+module_exit(vroot_exit);
+
--- linux-2.6.12.2/fs/quota.c	2005-06-22 02:38:37 +0200
+++ linux-2.6.12.2-vs2.0-rc6.1/fs/quota.c	2005-07-02 22:38:30 +0200
@@ -341,6 +343,10 @@ static int do_quotactl(struct super_bloc
 	return 0;
 }
 
+#ifdef CONFIG_BLK_DEV_VROOT
+extern struct block_device *vroot_get_real_bdev(struct block_device *);
+#endif
+
 /*
  * This is the system call interface. This communicates with
  * the user-level programs. Currently this only supports diskquota
--- linux-2.6.12.2/fs/quota.c	2005-06-22 02:38:37 +0200
+++ linux-2.6.12.2-vs2.0-rc6.1/fs/quota.c	2005-07-02 22:38:30 +0200
@@ -366,6 +372,18 @@ asmlinkage long sys_quotactl(unsigned in
 		putname(tmp);
 		if (IS_ERR(bdev))
 			return PTR_ERR(bdev);
+#ifdef CONFIG_BLK_DEV_VROOT
+		if (bdev && bdev->bd_inode &&
+			imajor(bdev->bd_inode) == VROOT_MAJOR) {
+			struct block_device *bdnew =
+				vroot_get_real_bdev(bdev);
+
+			bdput(bdev);
+			if (IS_ERR(bdnew))
+				return PTR_ERR(bdnew);
+			bdev = bdnew;
+		}
+#endif
 		sb = get_super(bdev);
 		bdput(bdev);
 		if (!sb)
--- linux-2.6.12.2/include/linux/major.h	2005-06-22 02:38:49 +0200
+++ linux-2.6.12.2-vs2.0-rc6.1/include/linux/major.h	2005-07-02 22:38:30 +0200
@@ -15,6 +15,7 @@
 #define HD_MAJOR		IDE0_MAJOR
 #define PTY_SLAVE_MAJOR		3
 #define TTY_MAJOR		4
+#define VROOT_MAJOR	4
 #define TTYAUX_MAJOR		5
 #define LP_MAJOR		6
 #define VCS_MAJOR		7
--- linux-2.6.12.2/include/linux/vroot.h	1970-01-01 01:00:00 +0100
+++ linux-2.6.12.2-vs2.0-rc6.1/include/linux/vroot.h	2005-07-02 22:38:30 +0200
@@ -0,0 +1,45 @@
+
+/*
+ * include/linux/vroot.h
+ *
+ * written by Herbert P�tzl, 9/11/2002
+ * ported to 2.6 by Herbert P�tzl, 30/12/2004
+ *
+ * Copyright (C) 2002-2005 by Herbert P�tzl.
+ * Redistribution of this file is permitted under the
+ * GNU General Public License.
+ */
+
+#ifndef _LINUX_VROOT_H
+#define _LINUX_VROOT_H
+
+
+#ifdef __KERNEL__
+
+/* Possible states of device */
+enum {
+	Vr_unbound,
+	Vr_bound,
+};
+
+struct vroot_device {
+	int		vr_number;
+	int		vr_refcnt;
+
+	struct semaphore	vr_ctl_mutex;
+	struct block_device    *vr_device;
+	int			vr_state;
+};
+
+#endif /* __KERNEL__ */
+
+#define MAX_VROOT_DEFAULT	8
+
+/*
+ * IOCTL commands --- we will commandeer 0x56 ('V')
+ */
+
+#define VROOT_SET_DEV		0x5600
+#define VROOT_CLR_DEV		0x5601
+
+#endif /* _LINUX_VROOT_H */