diff -NurpP linux-2.6.19-vs2.1.1.5/include/linux/vserver/Kbuild linux-2.6.19-vs2.1.1.5.1/include/linux/vserver/Kbuild --- linux-2.6.19-vs2.1.1.5/include/linux/vserver/Kbuild 2006-12-06 20:42:19 +0100 +++ linux-2.6.19-vs2.1.1.5.1/include/linux/vserver/Kbuild 2006-12-10 17:46:53 +0100 @@ -1,9 +1,10 @@ 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 sched_cmd.h signal_cmd.h debug_cmd.h + inode_cmd.h sched_cmd.h signal_cmd.h debug_cmd.h \ + device_cmd.h -unifdef-y += switch.h network.h monitor.h +unifdef-y += switch.h network.h monitor.h inode.h device.h unifdef-y += legacy.h diff -NurpP linux-2.6.19-vs2.1.1.5/include/linux/vserver/device_cmd.h linux-2.6.19-vs2.1.1.5.1/include/linux/vserver/device_cmd.h --- linux-2.6.19-vs2.1.1.5/include/linux/vserver/device_cmd.h 2006-12-08 02:07:23 +0100 +++ linux-2.6.19-vs2.1.1.5.1/include/linux/vserver/device_cmd.h 2006-12-10 21:50:20 +0100 @@ -29,11 +29,11 @@ struct vcmd_set_mapping_v0_x32 { #include -extern int vc_set_mapping(uint32_t, void __user *); +extern int vc_set_mapping(struct vx_info *, void __user *); #ifdef CONFIG_COMPAT -extern int vc_set_mapping_x32(uint32_t, void __user *); +extern int vc_set_mapping_x32(struct vx_info *, void __user *); #endif /* CONFIG_COMPAT */ diff -NurpP linux-2.6.19-vs2.1.1.5/kernel/vserver/Kconfig linux-2.6.19-vs2.1.1.5.1/kernel/vserver/Kconfig --- linux-2.6.19-vs2.1.1.5/kernel/vserver/Kconfig 2006-12-04 06:07:42 +0100 +++ linux-2.6.19-vs2.1.1.5.1/kernel/vserver/Kconfig 2006-12-10 17:31:22 +0100 @@ -76,6 +76,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 -NurpP linux-2.6.19-vs2.1.1.5/kernel/vserver/Makefile linux-2.6.19-vs2.1.1.5.1/kernel/vserver/Makefile --- linux-2.6.19-vs2.1.1.5/kernel/vserver/Makefile 2006-12-07 19:32:06 +0100 +++ linux-2.6.19-vs2.1.1.5.1/kernel/vserver/Makefile 2006-12-10 17:29:53 +0100 @@ -14,4 +14,5 @@ vserver-$(CONFIG_VSERVER_LEGACY) += lega vserver-$(CONFIG_VSERVER_LEGACYNET) += legacynet.o vserver-$(CONFIG_VSERVER_HISTORY) += history.o vserver-$(CONFIG_VSERVER_MONITOR) += monitor.o +vserver-$(CONFIG_VSERVER_DEVICE) += device.o diff -NurpP linux-2.6.19-vs2.1.1.5/kernel/vserver/device.c linux-2.6.19-vs2.1.1.5.1/kernel/vserver/device.c --- linux-2.6.19-vs2.1.1.5/kernel/vserver/device.c 1970-01-01 01:00:00 +0100 +++ linux-2.6.19-vs2.1.1.5.1/kernel/vserver/device.c 2006-12-11 02:04:39 +0100 @@ -0,0 +1,228 @@ +/* + * linux/kernel/vserver/device.c + * + * Virtual Server: Device Support + * + * Copyright (C) 2006 Herbert Pötzl + * + * V0.01 device mapping basics + * + */ + +#include +#include +#include +#include +#include +// #include + +#include +#include +#include +#include +#include +#include + + +#define DMAP_HASH_BITS 4 + +struct hlist_head dmap_main_hash[1 << DMAP_HASH_BITS]; + +static spinlock_t dmap_main_hash_lock = SPIN_LOCK_UNLOCKED; + + +struct vs_mapping { + struct hlist_node dm_hlist; + dev_t device; + dev_t target; + int flags; +}; + + +kmem_cache_t *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); + + head = &hash[__hashval(device, DMAP_HASH_BITS)]; + hlist_add_head(&vdm->dm_hlist, head); + spin_unlock(hash_lock); +} + +/* __unhash_mapping() + + * remove a mapping from the hash table */ + +static inline void __unhash_mapping(struct vx_info *vxi, struct vs_mapping *vdm) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + int device = vdm->device; + + spin_lock(hash_lock); + vxdprintk(VXD_CBIT(misc, 8), "__unhash_mapping: %p[#%d] %08x:%08x", + vxi, vxi ? vxi->vx_id : 0, device, vdm->target); + + hlist_del(&vdm->dm_hlist); + spin_unlock(hash_lock); +} + + + +static inline int __lookup_mapping(struct vx_info *vxi, + dev_t device, dev_t *target, int *flags) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + 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; + int ret; + + spin_lock(hash_lock); + hlist_for_each(pos, head) { + vdm = hlist_entry(pos, struct vs_mapping, dm_hlist); + + if (vdm->device == device) + goto found; + } + ret = 0; + goto out; +found: + if (target) + *target = vdm->target; + if (flags) + *flags = vdm->flags; + ret = 1; +out: + spin_unlock(hash_lock); + return ret; +} + + + + +int vs_map_device(struct vx_info *vxi, dev_t *device) +{ + dev_t target = ~0; + int ret, flags = 0; + + ret = __lookup_mapping(vxi, *device, &target, &flags); + if (!ret) + target = *device; + printk("ˇˇˇ mapping device: %08x target: %08x flags: %04x ret=%d\n", *device, target, flags, ret); + + *device = target; + return 0; +} + + + +int do_set_mapping(struct vx_info *vxi, dev_t device, dev_t target, int flags) +{ + struct vs_mapping *new; + + new = kmem_cache_alloc(dmap_cachep, SLAB_KERNEL); + if (!new) + return -ENOMEM; + + INIT_HLIST_NODE(&new->dm_hlist); + new->device = device; + new->target = target; + new->flags = flags; + + printk("ˇˇˇ device: %08x target: %08x\n", device, target); + __hash_mapping(vxi, new); + return 0; +} + + +static inline +int __user_device(const char __user *name, dev_t *dev) +{ + 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; + path_release(&nd); + return 0; +} + +int vc_set_mapping(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_mapping_v0 vc_data; + dev_t device = ~0, target = ~0; + int ret; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = __user_device(vc_data.device, &device); + if (ret) + return ret; + ret = __user_device(vc_data.target, &target); + if (ret) + return ret; + + return do_set_mapping(vxi, device, target, vc_data.flags); +} + +#ifdef CONFIG_COMPAT + +int vc_set_mapping_x32(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_mapping_v0_x32 vc_data; + dev_t device = ~0, target = ~0; + int ret; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = __user_device(compat_ptr(vc_data.device_ptr), &device); + if (ret) + return ret; + ret = __user_device(compat_ptr(vc_data.target_ptr), &target); + if (ret) + return ret; + + return do_set_mapping(vxi, device, target, vc_data.flags); +} + +#endif /* CONFIG_COMPAT */ + + diff -NurpP linux-2.6.19-vs2.1.1.5/kernel/vserver/switch.c linux-2.6.19-vs2.1.1.5.1/kernel/vserver/switch.c --- linux-2.6.19-vs2.1.1.5/kernel/vserver/switch.c 2006-12-05 18:15:48 +0100 +++ linux-2.6.19-vs2.1.1.5.1/kernel/vserver/switch.c 2006-12-10 21:51:25 +0100 @@ -13,6 +13,7 @@ * V0.06 added compat32 layer * V0.07 vcmd args and perms * V0.08 added status commands + * V0.09 added device commands * */ @@ -54,6 +55,7 @@ int vc_get_vci(uint32_t id) #include #include #include +#include #include #include @@ -220,6 +222,10 @@ long do_vcmd(uint32_t cmd, uint32_t id, case VCMD_net_remove: return vc_net_remove(nxi, data); +#ifdef CONFIG_VSERVER_DEVICE + case VCMD_set_mapping: + return __COMPAT(vc_set_mapping, vxi, data, compat); +#endif #ifdef CONFIG_VSERVER_HISTORY case VCMD_dump_history: return vc_dump_history(id); @@ -261,6 +267,8 @@ long do_vcmd(uint32_t cmd, uint32_t id, #define VCF_ARES 0x06 /* includes admin */ #define VCF_SETUP 0x08 +#define VCF_ZIDOK 0x10 /* zero id okay */ + static inline long do_vserver(uint32_t cmd, uint32_t id, void __user *data, int compat) @@ -341,6 +349,9 @@ 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); +#endif /* debug level admin commands */ #ifdef CONFIG_VSERVER_HISTORY __VCMD(dump_history, 9, VCA_NONE, 0); @@ -441,6 +452,9 @@ long do_vserver(uint32_t cmd, uint32_t i goto out; state = 6; + if (!id && (flags & VCF_ZIDOK)) + goto skip_id; + ret = -ESRCH; if (args & VCA_VXI) { vxi = lookup_vx_info(id); @@ -469,15 +483,15 @@ long do_vserver(uint32_t cmd, uint32_t i goto out_nxi; } } - +skip_id: state = 8; ret = do_vcmd(cmd, id, vxi, nxi, data, compat); out_nxi: - if (args & VCA_NXI) + if ((args & VCA_NXI) && nxi) put_nx_info(nxi); out_vxi: - if (args & VCA_VXI) + if ((args & VCA_VXI) && vxi) put_vx_info(vxi); out: vxdprintk(VXD_CBIT(switch, 1),