diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/fs/block_dev.c linux-2.6.22.9-vs2.3.0.26.4.dmap/fs/block_dev.c --- linux-2.6.22.9-vs2.3.0.26.4/fs/block_dev.c 2007-07-22 00:00:15.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/fs/block_dev.c 2007-10-10 21:22:38.000000000 +0200 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "internal.h" @@ -572,6 +573,7 @@ struct block_device *bdget(dev_t dev) bdev->bd_invalidated = 0; inode->i_mode = S_IFBLK; inode->i_rdev = dev; + inode->i_mdev = dev; inode->i_bdev = bdev; inode->i_data.a_ops = &def_blk_aops; mapping_set_gfp_mask(&inode->i_data, GFP_USER); @@ -610,6 +612,11 @@ EXPORT_SYMBOL(bdput); static struct block_device *bd_acquire(struct inode *inode) { struct block_device *bdev; + dev_t mdev; + + if (!vs_map_blkdev(inode->i_rdev, &mdev, DATTR_OPEN)) + return NULL; + inode->i_mdev = mdev; spin_lock(&bdev_lock); bdev = inode->i_bdev; @@ -620,7 +627,7 @@ static struct block_device *bd_acquire(s } spin_unlock(&bdev_lock); - bdev = bdget(inode->i_rdev); + bdev = bdget(mdev); if (bdev) { spin_lock(&bdev_lock); if (!inode->i_bdev) { diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/fs/char_dev.c linux-2.6.22.9-vs2.3.0.26.4.dmap/fs/char_dev.c --- linux-2.6.22.9-vs2.3.0.26.4/fs/char_dev.c 2007-07-21 23:58:44.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/fs/char_dev.c 2007-10-10 21:25:27.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef CONFIG_KMOD #include @@ -363,14 +364,21 @@ int chrdev_open(struct inode * inode, st struct cdev *p; struct cdev *new = NULL; int ret = 0; + dev_t mdev; + + if (!vs_map_chrdev(inode->i_rdev, &mdev, DATTR_OPEN)) + return -EPERM; + inode->i_mdev = mdev; spin_lock(&cdev_lock); p = inode->i_cdev; if (!p) { struct kobject *kobj; int idx; + spin_unlock(&cdev_lock); - kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); + + kobj = kobj_lookup(cdev_map, mdev, &idx); if (!kobj) return -ENXIO; new = container_of(kobj, struct cdev, kobj); diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/fs/inode.c linux-2.6.22.9-vs2.3.0.26.4.dmap/fs/inode.c --- linux-2.6.22.9-vs2.3.0.26.4/fs/inode.c 2007-09-29 14:12:10.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/fs/inode.c 2007-10-09 17:54:37.000000000 +0200 @@ -136,6 +136,7 @@ static struct inode *alloc_inode(struct inode->i_bdev = NULL; inode->i_cdev = NULL; inode->i_rdev = 0; + inode->i_mdev = 0; inode->dirtied_when = 0; if (security_inode_alloc(inode)) { if (inode->i_sb->s_op->destroy_inode) @@ -1410,9 +1411,11 @@ void init_special_inode(struct inode *in if (S_ISCHR(mode)) { inode->i_fop = &def_chr_fops; inode->i_rdev = rdev; + inode->i_mdev = rdev; } else if (S_ISBLK(mode)) { inode->i_fop = &def_blk_fops; inode->i_rdev = rdev; + inode->i_mdev = rdev; } else if (S_ISFIFO(mode)) inode->i_fop = &def_fifo_fops; else if (S_ISSOCK(mode)) diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/fs/namei.c linux-2.6.22.9-vs2.3.0.26.4.dmap/fs/namei.c --- linux-2.6.22.9-vs2.3.0.26.4/fs/namei.c 2007-09-29 14:12:10.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/fs/namei.c 2007-10-10 21:44:28.000000000 +0200 @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -1946,9 +1948,17 @@ int vfs_mknod(struct inode *dir, struct if (error) return error; - if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) + if (!(S_ISCHR(mode) || S_ISBLK(mode))) + goto okay; + + if (!capable(CAP_MKNOD)) return -EPERM; + if (S_ISCHR(mode) && !vs_chrdev_perm(dev, DATTR_CREATE)) + return -EPERM; + if (S_ISBLK(mode) && !vs_blkdev_perm(dev, DATTR_CREATE)) + return -EPERM; +okay: if (!dir->i_op || !dir->i_op->mknod) return -EPERM; diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/include/linux/fs.h linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/fs.h --- linux-2.6.22.9-vs2.3.0.26.4/include/linux/fs.h 2007-09-29 14:12:16.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/fs.h 2007-10-09 17:54:37.000000000 +0200 @@ -561,6 +561,7 @@ struct inode { gid_t i_gid; tag_t i_tag; dev_t i_rdev; + dev_t i_mdev; unsigned long i_version; loff_t i_size; #ifdef __NEED_I_SIZE_ORDERED @@ -695,12 +696,12 @@ static inline void i_size_write(struct i static inline unsigned iminor(const struct inode *inode) { - return MINOR(inode->i_rdev); + return MINOR(inode->i_mdev); } static inline unsigned imajor(const struct inode *inode) { - return MAJOR(inode->i_rdev); + return MAJOR(inode->i_mdev); } extern struct block_device *I_BDEV(struct inode *inode); diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/include/linux/vs_device.h linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vs_device.h --- linux-2.6.22.9-vs2.3.0.26.4/include/linux/vs_device.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vs_device.h 2007-10-10 18:22:52.000000000 +0200 @@ -0,0 +1,45 @@ +#ifndef _VS_DEVICE_H +#define _VS_DEVICE_H + +#include "vserver/base.h" +#include "vserver/device.h" +#include "vserver/debug.h" + + +#ifdef CONFIG_VSERVER_DEVICE + +int vs_map_device(struct vx_info *, dev_t, dev_t *, umode_t); + +#define vs_device_perm(v, d, m, p) \ + ((vs_map_device(current_vx_info(), d, NULL, m) & (p)) == (p)) + +#else + +static inline +int vs_map_device(struct vx_info *vxi, + dev_t device, dev_t *target, umode_t mode) +{ + if (target) + *target = device; + return ~0; +} + +#define vs_device_perm(v, d, m, p) ((p) == (p)) + +#endif + + +#define vs_map_chrdev(d, t, p) \ + ((vs_map_device(current_vx_info(), d, t, S_IFCHR) & (p)) == (p)) +#define vs_map_blkdev(d, t, p) \ + ((vs_map_device(current_vx_info(), d, t, S_IFBLK) & (p)) == (p)) + +#define vs_chrdev_perm(d, p) \ + vs_device_perm(current_vx_info(), d, S_IFCHR, p) +#define vs_blkdev_perm(d, p) \ + vs_device_perm(current_vx_info(), d, S_IFBLK, p) + + +#else +#warning duplicate inclusion +#endif diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/context.h linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/context.h --- linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/context.h 2007-09-29 14:12:16.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/context.h 2007-10-10 21:43:58.000000000 +0200 @@ -84,6 +84,7 @@ #include "sched_def.h" #include "cvirt_def.h" #include "cacct_def.h" +#include "device_def.h" struct _vx_info_pc { struct _vx_sched_pc sched_pc; @@ -116,6 +117,8 @@ struct vx_info { struct _vx_cvirt cvirt; /* virtual/bias stuff */ struct _vx_cacct cacct; /* context accounting */ + struct _vx_device dmap; /* default device map targets */ + #ifndef CONFIG_SMP struct _vx_info_pc info_pc; /* per cpu data */ #else diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/device_cmd.h linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/device_cmd.h --- linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/device_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/device_cmd.h 2007-10-10 14:29:55.000000000 +0200 @@ -0,0 +1,44 @@ +#ifndef _VX_DEVICE_CMD_H +#define _VX_DEVICE_CMD_H + + +/* device vserver commands */ + +#define VCMD_set_mapping VC_CMD(DEVICE, 1, 0) +#define VCMD_unset_mapping VC_CMD(DEVICE, 2, 0) + +struct vcmd_set_mapping_v0 { + const char __user *device; + const char __user *target; + uint32_t flags; +}; + + +#ifdef __KERNEL__ + +#ifdef CONFIG_COMPAT + +#include + +struct vcmd_set_mapping_v0_x32 { + compat_uptr_t device_ptr; + compat_uptr_t target_ptr; + uint32_t flags; +}; + +#endif /* CONFIG_COMPAT */ + +#include + +extern int vc_set_mapping(struct vx_info *, void __user *); +extern int vc_unset_mapping(struct vx_info *, void __user *); + +#ifdef CONFIG_COMPAT + +extern int vc_set_mapping_x32(struct vx_info *, void __user *); +extern int vc_unset_mapping_x32(struct vx_info *, void __user *); + +#endif /* CONFIG_COMPAT */ + +#endif /* __KERNEL__ */ +#endif /* _VX_DEVICE_CMD_H */ diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/device_def.h linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/device_def.h --- linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/device_def.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/device_def.h 2007-10-10 21:37:57.000000000 +0200 @@ -0,0 +1,17 @@ +#ifndef _VX_DEVICE_DEF_H +#define _VX_DEVICE_DEF_H + +#include + +struct vx_dmap_target { + dev_t target; + uint32_t flags; +}; + +struct _vx_device { +#ifdef CONFIG_VSERVER_DEVICE + struct vx_dmap_target targets[2]; +#endif +}; + +#endif /* _VX_DEVICE_DEF_H */ diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/device.h linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/device.h --- linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/device.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/device.h 2007-10-09 21:53:46.000000000 +0200 @@ -0,0 +1,15 @@ +#ifndef _VX_DEVICE_H +#define _VX_DEVICE_H + + +#define DATTR_CREATE 0x00000001 +#define DATTR_OPEN 0x00000002 + +#define DATTR_REMAP 0x00000010 + +#define DATTR_MASK 0x00000013 + + +#else /* _VX_DEVICE_H */ +#warning duplicate inclusion +#endif /* _VX_DEVICE_H */ diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/Kbuild linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/Kbuild --- linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/Kbuild 2007-09-29 14:12:16.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/Kbuild 2007-10-10 18:03:15.000000000 +0200 @@ -2,7 +2,7 @@ unifdef-y += context_cmd.h network_cmd.h space_cmd.h \ cacct_cmd.h cvirt_cmd.h limit_cmd.h dlimit_cmd.h \ inode_cmd.h tag_cmd.h sched_cmd.h signal_cmd.h \ - debug_cmd.h + debug_cmd.h device_cmd.h -unifdef-y += switch.h network.h monitor.h inode.h +unifdef-y += switch.h network.h monitor.h inode.h device.h diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/switch.h linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/switch.h --- linux-2.6.22.9-vs2.3.0.26.4/include/linux/vserver/switch.h 2007-09-29 14:12:16.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/include/linux/vserver/switch.h 2007-10-09 17:54:37.000000000 +0200 @@ -51,6 +51,8 @@ #define VC_CAT_VSETUP 1 #define VC_CAT_VHOST 2 +#define VC_CAT_DEVICE 6 + #define VC_CAT_VPROC 9 #define VC_CAT_PROCALT 10 #define VC_CAT_PROCMIG 11 diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/kernel/vserver/device.c linux-2.6.22.9-vs2.3.0.26.4.dmap/kernel/vserver/device.c --- linux-2.6.22.9-vs2.3.0.26.4/kernel/vserver/device.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/kernel/vserver/device.c 2007-10-10 21:38:40.000000000 +0200 @@ -0,0 +1,443 @@ +/* + * linux/kernel/vserver/device.c + * + * Linux-VServer: Device Support + * + * Copyright (C) 2006 Herbert Pötzl + * Copyright (C) 2007 Daniel Hokka Zakrisson + * + * V0.01 device mapping basics + * V0.02 added defaults + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#define DMAP_HASH_BITS 4 + + +struct vs_mapping { + union { + struct hlist_node hlist; + struct list_head list; + } u; +#define dm_hlist u.hlist +#define dm_list u.list + xid_t xid; + dev_t device; + struct vx_dmap_target target; +}; + + +static struct hlist_head dmap_main_hash[1 << DMAP_HASH_BITS]; + +static spinlock_t dmap_main_hash_lock = SPIN_LOCK_UNLOCKED; + +static struct vx_dmap_target dmap_defaults[2] = { + { .flags = DATTR_OPEN }, + { .flags = DATTR_OPEN }, +}; + + +struct kmem_cache *dmap_cachep __read_mostly; + +int __init dmap_cache_init(void) +{ + dmap_cachep = kmem_cache_create("dmap_cache", + sizeof(struct vs_mapping), 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + return 0; +} + +__initcall(dmap_cache_init); + + +static inline unsigned int __hashval(dev_t dev, int bits) +{ + return hash_long((unsigned long)dev, bits); +} + + +/* __hash_mapping() + * add the mapping to the hash table + */ +static inline void __hash_mapping(struct vx_info *vxi, struct vs_mapping *vdm) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + struct hlist_head *head, *hash = dmap_main_hash; + int device = vdm->device; + + spin_lock(hash_lock); + vxdprintk(VXD_CBIT(misc, 8), "__hash_mapping: %p[#%d] %08x:%08x", + vxi, vxi ? vxi->vx_id : 0, device, vdm->target.target); + + head = &hash[__hashval(device, DMAP_HASH_BITS)]; + hlist_add_head(&vdm->dm_hlist, head); + spin_unlock(hash_lock); +} + + +static inline int __mode_to_default(umode_t mode) +{ + switch (mode) { + case S_IFBLK: + return 0; + case S_IFCHR: + return 1; + default: + BUG(); + } +} + + +/* __set_default() + * set a default + */ +static inline void __set_default(struct vx_info *vxi, umode_t mode, + struct vx_dmap_target *vdmt) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + spin_lock(hash_lock); + + if (vxi) + vxi->dmap.targets[__mode_to_default(mode)] = *vdmt; + else + dmap_defaults[__mode_to_default(mode)] = *vdmt; + + + spin_unlock(hash_lock); + + vxdprintk(VXD_CBIT(misc, 8), "__set_default: %p[#%u] %08x %04x", + vxi, vxi ? vxi->vx_id : 0, vdmt->target, vdmt->flags); +} + + +/* __remove_default() + * remove a default + */ +static inline int __remove_default(struct vx_info *vxi, umode_t mode) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + spin_lock(hash_lock); + + if (vxi) + vxi->dmap.targets[__mode_to_default(mode)].flags = 0; + else /* remove == reset */ + dmap_defaults[__mode_to_default(mode)].flags = DATTR_OPEN | mode; + + spin_unlock(hash_lock); + return 0; +} + + +/* __find_mapping() + * find a mapping in the hash table + * + * caller must hold hash_lock + */ +static inline int __find_mapping(xid_t xid, dev_t device, umode_t mode, + struct vs_mapping **local, struct vs_mapping **global) +{ + struct hlist_head *hash = dmap_main_hash; + struct hlist_head *head = &hash[__hashval(device, DMAP_HASH_BITS)]; + struct hlist_node *pos; + struct vs_mapping *vdm; + + *local = NULL; + if (global) + *global = NULL; + + hlist_for_each(pos, head) { + vdm = hlist_entry(pos, struct vs_mapping, dm_hlist); + + if ((vdm->device == device) && + !((vdm->target.flags ^ mode) & S_IFMT)) { + if (vdm->xid == xid) { + *local = vdm; + return 1; + } else if (global && vdm->xid == 0) + *global = vdm; + } + } + + if (global && *global) + return 0; + else + return -ENOENT; +} + + +/* __lookup_mapping() + * find a mapping and store the result in target and flags + */ +static inline int __lookup_mapping(struct vx_info *vxi, + dev_t device, dev_t *target, int *flags, umode_t mode) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + struct vs_mapping *vdm, *global; + struct vx_dmap_target *vdmt; + int ret = 0; + xid_t xid = vxi->vx_id; + int index; + + spin_lock(hash_lock); + if (__find_mapping(xid, device, mode, &vdm, &global) > 0) { + ret = 1; + vdmt = &vdm->target; + goto found; + } + + index = __mode_to_default(mode); + if (vxi && vxi->dmap.targets[index].flags) { + ret = 2; + vdmt = &vxi->dmap.targets[index]; + } else if (global) { + ret = 3; + vdmt = &global->target; + goto found; + } else { + ret = 4; + vdmt = &dmap_defaults[index]; + } + +found: + if (target && (vdmt->flags & DATTR_REMAP)) + *target = vdmt->target; + else if (target) + *target = device; + if (flags) + *flags = vdmt->flags; + + spin_unlock(hash_lock); + + return ret; +} + + +/* __remove_mapping() + * remove a mapping from the hash table + */ +static inline int __remove_mapping(struct vx_info *vxi, dev_t device, + umode_t mode) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + struct vs_mapping *vdm = NULL; + int ret = 0; + + spin_lock(hash_lock); + + ret = __find_mapping((vxi ? vxi->vx_id : 0), device, mode, &vdm, + NULL); + vxdprintk(VXD_CBIT(misc, 8), "__remove_mapping: %p[#%d] %08x %04x", + vxi, vxi ? vxi->vx_id : 0, device, mode); + if (ret < 0) + goto out; + hlist_del(&vdm->dm_hlist); + +out: + spin_unlock(hash_lock); + if (vdm) + kmem_cache_free(dmap_cachep, vdm); + return ret; +} + + + +int vs_map_device(struct vx_info *vxi, + dev_t device, dev_t *target, umode_t mode) +{ + int ret, flags = DATTR_MASK; + + if (!vxi) { + if (target) + *target = device; + goto out; + } + ret = __lookup_mapping(vxi, device, target, &flags, mode); + vxdprintk(VXD_CBIT(misc, 8), "vs_map_device: %08x target: %08x flags: %04x mode: %04x mapped=%d", + device, target ? *target : 0, flags, mode, ret); +out: + return (flags & DATTR_MASK); +} + + + +static int do_set_mapping(struct vx_info *vxi, + dev_t device, dev_t target, int flags, umode_t mode) +{ + if (device) { + struct vs_mapping *new; + + new = kmem_cache_alloc(dmap_cachep, GFP_KERNEL); + if (!new) + return -ENOMEM; + + INIT_HLIST_NODE(&new->dm_hlist); + new->device = device; + new->target.target = target; + new->target.flags = flags | mode; + new->xid = (vxi ? vxi->vx_id : 0); + + vxdprintk(VXD_CBIT(misc, 8), "do_set_mapping: %08x target: %08x flags: %04x", device, target, flags); + __hash_mapping(vxi, new); + } else { + struct vx_dmap_target new = { + .target = target, + .flags = flags | mode, + }; + __set_default(vxi, mode, &new); + } + return 0; +} + + +static int do_unset_mapping(struct vx_info *vxi, + dev_t device, dev_t target, int flags, umode_t mode) +{ + int ret = -EINVAL; + + if (device) { + ret = __remove_mapping(vxi, device, mode); + if (ret < 0) + goto out; + } else { + ret = __remove_default(vxi, mode); + if (ret < 0) + goto out; + } + +out: + return ret; +} + + +static inline int __user_device(const char __user *name, dev_t *dev, + umode_t *mode) +{ + struct nameidata nd; + int ret; + + if (!name) { + *dev = 0; + return 0; + } + ret = user_path_walk_link(name, &nd); + if (ret) + return ret; + if (nd.dentry->d_inode) { + *dev = nd.dentry->d_inode->i_rdev; + *mode = nd.dentry->d_inode->i_mode; + } + path_release(&nd); + return 0; +} + +static inline int __mapping_mode(dev_t device, dev_t target, + umode_t device_mode, umode_t target_mode, umode_t *mode) +{ + if (device) + *mode = device_mode & S_IFMT; + else if (target) + *mode = target_mode & S_IFMT; + else + *mode = 0; + + /* if both given, device and target mode have to match */ + if (device && target && + ((device_mode ^ target_mode) & S_IFMT)) + return -EINVAL; + return 0; +} + + +static inline int do_mapping(struct vx_info *vxi, const char __user *device_path, + const char __user *target_path, int flags, int set) +{ + dev_t device = ~0, target = ~0; + umode_t device_mode = 0, target_mode = 0, mode; + int ret; + + ret = __user_device(device_path, &device, &device_mode); + if (ret) + return ret; + ret = __user_device(target_path, &target, &target_mode); + if (ret) + return ret; + + ret = __mapping_mode(device, target, + device_mode, target_mode, &mode); + if (ret) + return ret; + + if (set) + return do_set_mapping(vxi, device, target, + flags, mode); + else + return do_unset_mapping(vxi, device, target, + flags, mode); +} + + +int vc_set_mapping(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_mapping_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_mapping(vxi, vc_data.device, vc_data.target, + vc_data.flags, 1); +} + +int vc_unset_mapping(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_mapping_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_mapping(vxi, vc_data.device, vc_data.target, + vc_data.flags, 0); +} + + +#ifdef CONFIG_COMPAT + +int vc_set_mapping_x32(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_mapping_v0_x32 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_mapping(vxi, compat_ptr(vc_data.device_ptr), + compat_ptr(vc_data.target_ptr), vc_data.flags, 1); +} + +int vc_unset_mapping_x32(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_mapping_v0_x32 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_mapping(vxi, compat_ptr(vc_data.device_ptr), + compat_ptr(vc_data.target_ptr), vc_data.flags, 0); +} + +#endif /* CONFIG_COMPAT */ + + diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/kernel/vserver/Kconfig linux-2.6.22.9-vs2.3.0.26.4.dmap/kernel/vserver/Kconfig --- linux-2.6.22.9-vs2.3.0.26.4/kernel/vserver/Kconfig 2007-09-29 14:12:16.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/kernel/vserver/Kconfig 2007-10-09 17:54:37.000000000 +0200 @@ -44,6 +44,13 @@ config VSERVER_VTIME this adds some overhead to the time functions and therefore should not be enabled without good reason. +config VSERVER_DEVICE + bool "Enable Guest Device Mapping" + depends on EXPERIMENTAL + default n + help + This enables generic device remapping. + config VSERVER_PROC_SECURE bool "Enable Proc Security" depends on PROC_FS diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/kernel/vserver/Makefile linux-2.6.22.9-vs2.3.0.26.4.dmap/kernel/vserver/Makefile --- linux-2.6.22.9-vs2.3.0.26.4/kernel/vserver/Makefile 2007-09-29 14:12:16.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/kernel/vserver/Makefile 2007-10-09 17:54:37.000000000 +0200 @@ -14,4 +14,5 @@ vserver-$(CONFIG_PROC_FS) += proc.o vserver-$(CONFIG_VSERVER_DEBUG) += sysctl.o debug.o vserver-$(CONFIG_VSERVER_HISTORY) += history.o vserver-$(CONFIG_VSERVER_MONITOR) += monitor.o +vserver-$(CONFIG_VSERVER_DEVICE) += device.o diff -Nurp linux-2.6.22.9-vs2.3.0.26.4/kernel/vserver/switch.c linux-2.6.22.9-vs2.3.0.26.4.dmap/kernel/vserver/switch.c --- linux-2.6.22.9-vs2.3.0.26.4/kernel/vserver/switch.c 2007-09-29 14:12:16.000000000 +0200 +++ linux-2.6.22.9-vs2.3.0.26.4.dmap/kernel/vserver/switch.c 2007-10-10 15:12:16.000000000 +0200 @@ -15,6 +15,7 @@ * V0.08 added status commands * V0.09 added tag commands * V0.10 added oom bias + * V0.11 added device commands * */ @@ -49,6 +50,7 @@ int vc_get_vci(uint32_t id) #include #include #include +#include #include #include @@ -245,6 +247,13 @@ long do_vcmd(uint32_t cmd, uint32_t id, case VCMD_get_match_ipv6: return vc_get_match_ipv6(nxi, data); #endif */ + +#ifdef CONFIG_VSERVER_DEVICE + case VCMD_set_mapping: + return __COMPAT(vc_set_mapping, vxi, data, compat); + case VCMD_unset_mapping: + return __COMPAT(vc_unset_mapping, vxi, data, compat); +#endif #ifdef CONFIG_VSERVER_HISTORY case VCMD_dump_history: return vc_dump_history(id); @@ -371,6 +380,10 @@ long do_vserver(uint32_t cmd, uint32_t i __VCMD(add_dlimit, 8, VCA_NONE, VCF_ARES); __VCMD(rem_dlimit, 8, VCA_NONE, VCF_ARES); +#ifdef CONFIG_VSERVER_DEVICE + __VCMD(set_mapping, 8, VCA_VXI, VCF_ARES|VCF_ZIDOK); + __VCMD(unset_mapping, 8, VCA_VXI, VCF_ARES|VCF_ZIDOK); +#endif /* debug level admin commands */ #ifdef CONFIG_VSERVER_HISTORY __VCMD(dump_history, 9, VCA_NONE, 0);