; ; Virtual Root Device (for Quota) ; ; (C) 2002-2003 Herbert Pötzl ; ; Changelog: ; ; 0.10 - first public release ; 0.11 - removed quota capability ; - whitespace cleanups ; 0.12 - fixed modules export ; 0.13 - added (non)debug mode ; 0.14 - fixed major.h include ; - changed max_vroot to 8 ; ; this patch is free software; you can redistribute it and/or ; modify it under the terms of the GNU General Public License ; as published by the Free Software Foundation; either version 2 ; of the License, or (at your option) any later version. ; ; this patch is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; diff -NurpP --minimal linux-2.4.21-vs1.00/Documentation/Configure.help linux-2.4.21-vs1.00-vr0.14/Documentation/Configure.help --- linux-2.4.21-vs1.00/Documentation/Configure.help Sat Nov 1 11:14:23 2003 +++ linux-2.4.21-vs1.00-vr0.14/Documentation/Configure.help Thu Nov 6 22:39:13 2003 @@ -517,6 +517,11 @@ CONFIG_BLK_DEV_LOOP Most users will answer N here. +Virtual Root device support +CONFIG_BLK_DEV_VROOT + Saying Y here will allow you to use quota/fs ioctls on a shared + partition within a virtual server without compromising security. + Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL) CONFIG_BLK_DEV_UMEM Saying Y here will include support for the MM5415 family of diff -NurpP --minimal linux-2.4.21-vs1.00/drivers/block/Config.in linux-2.4.21-vs1.00-vr0.14/drivers/block/Config.in --- linux-2.4.21-vs1.00/drivers/block/Config.in Fri Nov 29 00:53:12 2002 +++ linux-2.4.21-vs1.00-vr0.14/drivers/block/Config.in Thu Nov 6 22:39:13 2003 @@ -40,6 +40,7 @@ dep_tristate 'Mylex DAC960/DAC1100 PCI R dep_tristate 'Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL)' CONFIG_BLK_DEV_UMEM $CONFIG_PCI $CONFIG_EXPERIMENTAL tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +tristate 'Virtual Root device support' CONFIG_BLK_DEV_VROOT dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET tristate 'RAM disk support' CONFIG_BLK_DEV_RAM diff -NurpP --minimal linux-2.4.21-vs1.00/drivers/block/Makefile linux-2.4.21-vs1.00-vr0.14/drivers/block/Makefile --- linux-2.4.21-vs1.00/drivers/block/Makefile Fri Jun 13 16:51:32 2003 +++ linux-2.4.21-vs1.00-vr0.14/drivers/block/Makefile Thu Nov 6 22:39:13 2003 @@ -31,6 +31,7 @@ obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss. obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o +obj-$(CONFIG_BLK_DEV_VROOT) += vroot.o subdir-$(CONFIG_PARIDE) += paride diff -NurpP --minimal linux-2.4.21-vs1.00/drivers/block/vroot.c linux-2.4.21-vs1.00-vr0.14/drivers/block/vroot.c --- linux-2.4.21-vs1.00/drivers/block/vroot.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.21-vs1.00-vr0.14/drivers/block/vroot.c Thu Nov 6 22:39:13 2003 @@ -0,0 +1,328 @@ +/* + * linux/drivers/block/vroot.c + * + * Written by Herbert Pötzl, 9/11/2002 + * + * based on the loop.c code by Theodore Ts'o. + * + * Copyright 2002-2003 by Herbert Pötzl. + * Redistribution of this file is permitted under the + * GNU General Public License. + * + */ + +#define MAJOR_NR VROOT_MAJOR + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "vroot.h" + +static int max_vroot = 8; +static struct vroot_device *vroot_dev; +static devfs_handle_t devfs_handle; /* For the directory */ + +#ifdef MODULE +typedef kdev_t (*vroot_get_dev_f)(int dev); + +extern int register_vroot_get_dev(vroot_get_dev_f); +extern int unregister_vroot_get_dev(vroot_get_dev_f); + +static kdev_t _vroot_get_dev(int dev) +#else + kdev_t vroot_get_dev(int dev) +#endif +{ + struct vroot_device *vr; + + if (dev >= max_vroot) + return NODEV; + + vr = &vroot_dev[dev]; + if (vr->vr_state != Vr_bound) + return NODEV; + dprintk(KERN_INFO "vroot[%d]_get_dev: dev(%d,%d)\n", + dev, MAJOR(vr->vr_device), MINOR(vr->vr_device)); + return vr->vr_device; +} + +static int vroot_set_dev( + struct vroot_device *vr, + struct file *vr_file, + kdev_t dev, + unsigned int arg) +{ + struct file *file; + struct inode *inode; + int error; + + MOD_INC_USE_COUNT; + + 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)) { + vr->vr_device = inode->i_rdev; + if (vr->vr_device == dev) { + error = -EBUSY; + goto out_fput; + } + } else + goto out_fput; + + dprintk(KERN_INFO "vroot[%d]_set_dev: dev(%d,%d)\n", + vr->vr_number, + MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); + + vr->vr_state = Vr_bound; + fput(file); + return 0; + out_fput: + fput(file); + out: + MOD_DEC_USE_COUNT; + return error; +} + +static int vroot_clr_dev( + struct vroot_device *vr, + struct file *vr_file, + kdev_t dev) +{ + if (vr->vr_state != Vr_bound) + return -ENXIO; + if (vr->vr_refcnt > 1) /* we needed one fd for the ioctl */ + return -EBUSY; + + dprintk(KERN_INFO "vroot[%d]_clr_dev: dev(%d,%d)\n", + vr->vr_number, + MAJOR(vr->vr_device), MINOR(vr->vr_device)); + + vr->vr_state = Vr_unbound; + vr->vr_device = NODEV; + MOD_DEC_USE_COUNT; + return 0; +} + +static int vroot_make_request( + request_queue_t *q, + int rw, + struct buffer_head *rbh) +{ + if (!buffer_locked(rbh)) + BUG(); + + if (MINOR(rbh->b_rdev) >= max_vroot) + goto out; + + dprintk(KERN_WARNING "vroot[%d]_make_request: denied.\n", + MINOR(rbh->b_rdev)); + out: + buffer_IO_error(rbh); + return 0; +} + +static int vr_ioctl( + struct inode * inode, + struct file * file, + unsigned int cmd, + unsigned long arg) +{ + struct vroot_device *vr; + int dev, err; + + if (!inode) + return -EINVAL; + if (MAJOR(inode->i_rdev) != MAJOR_NR) { + dprintk(KERN_WARNING "vr_ioctl: pseudo-major != %d\n", + MAJOR_NR); + return -ENODEV; + } + dev = MINOR(inode->i_rdev); + if (dev >= max_vroot) + return -ENODEV; + vr = &vroot_dev[dev]; + down(&vr->vr_ctl_mutex); + switch (cmd) { + case VROOT_SET_DEV: + err = vroot_set_dev(vr, file, inode->i_rdev, arg); + break; + case VROOT_CLR_DEV: + err = vroot_clr_dev(vr, file, inode->i_rdev); + 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; + int dev; + + if (!inode) + return -EINVAL; + if (MAJOR(inode->i_rdev) != MAJOR_NR) { + dprintk(KERN_WARNING "vr_open: pseudo-major != %d\n", MAJOR_NR); + return -ENODEV; + } + dev = MINOR(inode->i_rdev); + if (dev >= max_vroot) + return -ENODEV; + + vr = &vroot_dev[dev]; + MOD_INC_USE_COUNT; + 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; + int dev; + + if (!inode) + return 0; + if (MAJOR(inode->i_rdev) != MAJOR_NR) { + dprintk(KERN_WARNING "vr_release: pseudo-major != %d\n", + MAJOR_NR); + return 0; + } + dev = MINOR(inode->i_rdev); + if (dev >= max_vroot) + return 0; + + vr = &vroot_dev[dev]; + down(&vr->vr_ctl_mutex); + + vr->vr_refcnt--; + up(&vr->vr_ctl_mutex); + MOD_DEC_USE_COUNT; + return 0; +} + +static struct block_device_operations vr_fops = { + owner: THIS_MODULE, + open: vr_open, + release: vr_release, + ioctl: vr_ioctl, +}; + +/* + * And now the modules code and kernel interface. + */ +MODULE_PARM(max_vroot, "i"); +MODULE_PARM_DESC(max_vroot, "Maximum number of vroot devices (1-256)"); +MODULE_LICENSE("GPL"); + +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)) { + printk(KERN_WARNING "vroot: invalid max_vroot (must be between" + " 1 and 256), using default (4)\n"); + max_vroot = 4; + } + + if (devfs_register_blkdev(MAJOR_NR, "vroot", &vr_fops)) { + printk(KERN_WARNING "Unable to get major number %d for vroot" + " device\n", MAJOR_NR); + return -EIO; + } + + devfs_handle = devfs_mk_dir(NULL, "vroot", NULL); + devfs_register_series(devfs_handle, "%u", max_vroot, + DEVFS_FL_DEFAULT, MAJOR_NR, 0, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + &vr_fops, NULL); + + vroot_dev = kmalloc(max_vroot * sizeof(struct vroot_device), GFP_KERNEL); + if (!vroot_dev) + return -ENOMEM; + + blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), vroot_make_request); + + for (i = 0; i < max_vroot; i++) { + struct vroot_device *vr = &vroot_dev[i]; + memset(vr, 0, sizeof(struct vroot_device)); + init_MUTEX(&vr->vr_ctl_mutex); + vr->vr_number = i; + vr->vr_state = Vr_unbound; + } + + for (i = 0; i < max_vroot; i++) + register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &vr_fops, 0); + +#ifdef MODULE + register_vroot_get_dev(_vroot_get_dev); +#endif + printk(KERN_INFO "vroot: loaded (max %d devices)\n", max_vroot); + return 0; +} + +void vroot_exit(void) +{ +#ifdef MODULE + unregister_vroot_get_dev(_vroot_get_dev); +#endif + devfs_unregister(devfs_handle); + if (devfs_unregister_blkdev(MAJOR_NR, "vroot")) + printk(KERN_WARNING "vroot: cannot unregister blkdev\n"); + + kfree(vroot_dev); +} + +module_init(vroot_init); +module_exit(vroot_exit); + +#ifndef MODULE +static int __init max_vroot_setup(char *str) +{ + max_vroot = simple_strtol(str, NULL, 0); + return 1; +} + +__setup("max_vroot=", max_vroot_setup); + +#endif diff -NurpP --minimal linux-2.4.21-vs1.00/drivers/block/vroot.h linux-2.4.21-vs1.00-vr0.14/drivers/block/vroot.h --- linux-2.4.21-vs1.00/drivers/block/vroot.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.21-vs1.00-vr0.14/drivers/block/vroot.h Thu Nov 6 22:39:13 2003 @@ -0,0 +1,44 @@ +#ifndef _LINUX_VROOT_H +#define _LINUX_VROOT_H + +#include + +/* + * linux/drivers/block/vroot.h + * + * Written by Herbert Pötzl, 9/11/2002 + * + * Copyright 2002-2003 by Herbert Pötzl. + * Redistribution of this file is permitted under the + * GNU General Public License. + */ + +#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; + kdev_t vr_device; + int vr_state; +}; + +#define dprintk(...) /* printk(__VA_ARGS__) */ + +#endif /* __KERNEL__ */ + +/* + * IOCTL commands --- we will commandeer 0x56 ('V') + */ + +#define VROOT_SET_DEV 0x5600 +#define VROOT_CLR_DEV 0x5601 + +#endif diff -NurpP --minimal linux-2.4.21-vs1.00/fs/Makefile linux-2.4.21-vs1.00-vr0.14/fs/Makefile --- linux-2.4.21-vs1.00/fs/Makefile Fri Nov 29 00:53:15 2002 +++ linux-2.4.21-vs1.00-vr0.14/fs/Makefile Thu Nov 6 22:39:13 2003 @@ -7,7 +7,7 @@ O_TARGET := fs.o -export-objs := filesystems.o open.o dcache.o buffer.o +export-objs := filesystems.o open.o dcache.o buffer.o dquot.o mod-subdirs := nls obj-y := open.o read_write.o devices.o file_table.o buffer.o \ diff -NurpP --minimal linux-2.4.21-vs1.00/fs/dquot.c linux-2.4.21-vs1.00-vr0.14/fs/dquot.c --- linux-2.4.21-vs1.00/fs/dquot.c Sat Nov 1 10:50:41 2003 +++ linux-2.4.21-vs1.00-vr0.14/fs/dquot.c Thu Nov 6 22:39:13 2003 @@ -61,9 +61,13 @@ #include #include #include +#include +#include +#include #include + #define __DQUOT_VERSION__ "dquot_6.4.0" int nr_dquots, nr_free_dquots; @@ -1373,6 +1377,51 @@ out_lock: return error; } +#if defined(CONFIG_BLK_DEV_VROOT) || defined(CONFIG_BLK_DEV_VROOT_MODULE) +#if defined(CONFIG_BLK_DEV_VROOT_MODULE) + +static rwlock_t dquot_vroot_lock = RW_LOCK_UNLOCKED; + +typedef kdev_t (*vroot_get_dev_f)(int dev); + +static vroot_get_dev_f vroot_get_dev = NULL; + +int register_vroot_get_dev(vroot_get_dev_f func) +{ + int ret = -EBUSY; + + write_lock(&dquot_vroot_lock); + if (!vroot_get_dev) { + vroot_get_dev = func; + ret = 0; + } + write_unlock(&dquot_vroot_lock); + return ret; +} + +int unregister_vroot_get_dev(vroot_get_dev_f func) +{ + int ret = -EINVAL; + + write_lock(&dquot_vroot_lock); + if (vroot_get_dev == func) { + vroot_get_dev = NULL; + ret = 0; + } + write_unlock(&dquot_vroot_lock); + return ret; +} + +EXPORT_SYMBOL(register_vroot_get_dev); +EXPORT_SYMBOL(unregister_vroot_get_dev); + +#else /* CONFIG_BLK_DEV_VROOT */ + +extern kdev_t vroot_get_dev(int dev); + +#endif +#endif + /* * This is the system call interface. This communicates with * the user-level programs. Currently this only supports diskquota @@ -1429,6 +1478,19 @@ asmlinkage long sys_quotactl(int cmd, co if (!S_ISBLK(mode)) goto out; ret = -ENODEV; +#if defined(CONFIG_BLK_DEV_VROOT) || defined(CONFIG_BLK_DEV_VROOT_MODULE) + if (MAJOR(dev) == VROOT_MAJOR) { +#ifdef CONFIG_BLK_DEV_VROOT_MODULE + read_lock(&dquot_vroot_lock); + dev = (vroot_get_dev) ? vroot_get_dev(MINOR(dev)) : NODEV; + read_unlock(&dquot_vroot_lock); +#else + dev = vroot_get_dev(MINOR(dev)); +#endif + if (dev == NODEV) + goto out; + } +#endif sb = get_super(dev); if (!sb) goto out; diff -NurpP --minimal linux-2.4.21-vs1.00/include/linux/major.h linux-2.4.21-vs1.00-vr0.14/include/linux/major.h --- linux-2.4.21-vs1.00/include/linux/major.h Fri Jun 13 16:51:38 2003 +++ linux-2.4.21-vs1.00-vr0.14/include/linux/major.h Thu Nov 6 22:39:13 2003 @@ -24,6 +24,7 @@ #define PTY_SLAVE_MAJOR 3 #define HD_MAJOR IDE0_MAJOR #define TTY_MAJOR 4 +#define VROOT_MAJOR 4 #define TTYAUX_MAJOR 5 #define LP_MAJOR 6 #define VCS_MAJOR 7