X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fvserver%2Fnetwork.c;h=9dd16371934a1e89953cd95e53f7d063e80e4508;hb=refs%2Fremotes%2Fvserver;hp=1a8272fdd374f65415796bd81f4b8dcf5965189c;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/kernel/vserver/network.c b/kernel/vserver/network.c index 1a8272fdd..9dd163719 100644 --- a/kernel/vserver/network.c +++ b/kernel/vserver/network.c @@ -3,23 +3,29 @@ * * Virtual Server: Network Support * - * Copyright (C) 2003-2006 Herbert Pötzl + * Copyright (C) 2003-2007 Herbert Pötzl * * V0.01 broken out from vcontext V0.05 * V0.02 cleaned up implementation * V0.03 added equiv nx commands * V0.04 switch to RCU based hash * V0.05 and back to locking again - * V0.06 have __create claim() the nxi + * V0.06 changed vcmds to nxi arg + * V0.07 have __create claim() the nxi * */ #include -#include #include #include #include +#include +#include + + +atomic_t nx_global_ctotal = ATOMIC_INIT(0); +atomic_t nx_global_cactive = ATOMIC_INIT(0); /* __alloc_nx_info() @@ -51,6 +57,7 @@ static struct nx_info *__alloc_nx_info(nid_t nid) vxdprintk(VXD_CBIT(nid, 0), "alloc_nx_info(%d) = %p", nid, new); + atomic_inc(&nx_global_ctotal); return new; } @@ -71,6 +78,7 @@ static void __dealloc_nx_info(struct nx_info *nxi) nxi->nx_state |= NXS_RELEASED; kfree(nxi); + atomic_dec(&nx_global_ctotal); } static void __shutdown_nx_info(struct nx_info *nxi) @@ -131,6 +139,7 @@ static inline void __hash_nx_info(struct nx_info *nxi) nxi->nx_state |= NXS_HASHED; head = &nx_info_hash[__hashval(nxi->nx_id)]; hlist_add_head(&nxi->nx_hlist, head); + atomic_inc(&nx_global_cactive); } /* __unhash_nx_info() @@ -140,16 +149,19 @@ static inline void __hash_nx_info(struct nx_info *nxi) static inline void __unhash_nx_info(struct nx_info *nxi) { + vxd_assert_lock(&nx_info_hash_lock); vxdprintk(VXD_CBIT(nid, 4), - "__unhash_nx_info: %p[#%d]", nxi, nxi->nx_id); + "__unhash_nx_info: %p[#%d.%d.%d]", nxi, nxi->nx_id, + atomic_read(&nxi->nx_usecnt), atomic_read(&nxi->nx_tasks)); - spin_lock(&nx_info_hash_lock); /* context must be hashed */ BUG_ON(!nx_info_state(nxi, NXS_HASHED)); + /* but without tasks */ + BUG_ON(atomic_read(&nxi->nx_tasks)); nxi->nx_state &= ~NXS_HASHED; hlist_del(&nxi->nx_hlist); - spin_unlock(&nx_info_hash_lock); + atomic_dec(&nx_global_cactive); } @@ -222,6 +234,7 @@ static struct nx_info * __create_nx_info(int id) /* dynamic context requested */ if (id == NX_DYNAMIC_ID) { +#ifdef CONFIG_VSERVER_DYNAMIC_IDS id = __nx_dynamic_id(); if (!id) { printk(KERN_ERR "no dynamic context available.\n"); @@ -229,6 +242,11 @@ static struct nx_info * __create_nx_info(int id) goto out_unlock; } new->nx_id = id; +#else + printk(KERN_ERR "dynamic contexts disabled.\n"); + nxi = ERR_PTR(-EINVAL); + goto out_unlock; +#endif } /* static context requested */ else if ((nxi = __lookup_nx_info(id))) { @@ -270,7 +288,9 @@ out_unlock: void unhash_nx_info(struct nx_info *nxi) { __shutdown_nx_info(nxi); + spin_lock(&nx_info_hash_lock); __unhash_nx_info(nxi); + spin_unlock(&nx_info_hash_lock); } #ifdef CONFIG_VSERVER_LEGACYNET @@ -318,10 +338,23 @@ int nid_is_hashed(nid_t nid) #ifdef CONFIG_PROC_FS +/* get_nid_list() + + * get a subset of hashed nids for proc + * assumes size is at least one */ + int get_nid_list(int index, unsigned int *nids, int size) { int hindex, nr_nids = 0; + /* only show current and children */ + if (!nx_check(0, VS_ADMIN|VS_WATCH)) { + if (index > 0) + return 0; + nids[nr_nids] = nx_current_nid(); + return 1; + } + for (hindex = 0; hindex < NX_HASH_SIZE; hindex++) { struct hlist_head *head = &nx_info_hash[hindex]; struct hlist_node *pos; @@ -368,6 +401,13 @@ int nx_migrate_task(struct task_struct *p, struct nx_info *nxi) atomic_read(&nxi->nx_usecnt), atomic_read(&nxi->nx_tasks)); + if (nx_info_flags(nxi, NXF_INFO_PRIVATE, 0) && + !nx_info_flags(nxi, NXF_STATE_SETUP, 0)) + return -EACCES; + + if (nx_info_state(nxi, NXS_SHUTDOWN)) + return -EFAULT; + /* maybe disallow this completely? */ old_nxi = task_get_nx_info(p); if (old_nxi == nxi) @@ -418,6 +458,8 @@ int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) if (!nxi) return 1; + if (!dev) + goto out; in_dev = in_dev_get(dev); if (!in_dev) goto out; @@ -440,7 +482,7 @@ out: * sk: the socket to check against * addr: the address in question (must be != 0) */ -static inline int __addr_in_socket(struct sock *sk, uint32_t addr) +static inline int __addr_in_socket(const struct sock *sk, uint32_t addr) { struct nx_info *nxi = sk->sk_nx_info; uint32_t saddr = inet_rcv_saddr(sk); @@ -463,7 +505,7 @@ static inline int __addr_in_socket(struct sock *sk, uint32_t addr) } -int nx_addr_conflict(struct nx_info *nxi, uint32_t addr, struct sock *sk) +int nx_addr_conflict(struct nx_info *nxi, uint32_t addr, const struct sock *sk) { vxdprintk(VXD_CBIT(net, 2), "nx_addr_conflict(%p,%p) %d.%d,%d.%d", @@ -528,7 +570,7 @@ int vc_task_nid(uint32_t id, void __user *data) if (id) { struct task_struct *tsk; - if (!vx_check(0, VX_ADMIN|VX_WATCH)) + if (!nx_check(0, VS_ADMIN|VS_WATCH)) return -EPERM; read_lock(&tasklist_lock); @@ -542,22 +584,11 @@ int vc_task_nid(uint32_t id, void __user *data) } -int vc_nx_info(uint32_t id, void __user *data) +int vc_nx_info(struct nx_info *nxi, void __user *data) { - struct nx_info *nxi; struct vcmd_nx_info_v0 vc_data; - if (!vx_check(0, VX_ADMIN)) - return -ENOSYS; - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - nxi = lookup_nx_info(id); - if (!nxi) - return -ESRCH; - vc_data.nid = nxi->nx_id; - put_nx_info(nxi); if (copy_to_user (data, &vc_data, sizeof(vc_data))) return -EFAULT; @@ -573,12 +604,10 @@ int vc_net_create(uint32_t nid, void __user *data) struct nx_info *new_nxi; int ret; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; if (data && copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; - if ((nid > MAX_S_CONTEXT) && (nid != VX_DYNAMIC_ID)) + if ((nid > MAX_S_CONTEXT) && (nid != NX_DYNAMIC_ID)) return -EINVAL; if (nid < 2) return -EINVAL; @@ -611,29 +640,16 @@ out: } -int vc_net_migrate(uint32_t id, void __user *data) +int vc_net_migrate(struct nx_info *nxi, void __user *data) { - struct nx_info *nxi; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - nxi = lookup_nx_info(id); - if (!nxi) - return -ESRCH; - nx_migrate_task(current, nxi); - put_nx_info(nxi); - return 0; + return nx_migrate_task(current, nxi); } -int vc_net_add(uint32_t nid, void __user *data) +int vc_net_add(struct nx_info *nxi, void __user *data) { struct vcmd_net_addr_v0 vc_data; - struct nx_info *nxi; int index, pos, ret = 0; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; if (data && copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; @@ -647,10 +663,6 @@ int vc_net_add(uint32_t nid, void __user *data) break; } - nxi = lookup_nx_info(nid); - if (!nxi) - return -ESRCH; - switch (vc_data.type) { case NXA_TYPE_IPV4: index = 0; @@ -673,130 +685,82 @@ int vc_net_add(uint32_t nid, void __user *data) ret = -EINVAL; break; } - - put_nx_info(nxi); return ret; } -int vc_net_remove(uint32_t nid, void __user *data) +int vc_net_remove(struct nx_info * nxi, void __user *data) { struct vcmd_net_addr_v0 vc_data; - struct nx_info *nxi; - int ret = 0; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; if (data && copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; - nxi = lookup_nx_info(nid); - if (!nxi) - return -ESRCH; - switch (vc_data.type) { case NXA_TYPE_ANY: nxi->nbipv4 = 0; break; default: - ret = -EINVAL; - break; + return -EINVAL; } - - put_nx_info(nxi); - return ret; + return 0; } -int vc_get_nflags(uint32_t id, void __user *data) +int vc_get_nflags(struct nx_info *nxi, void __user *data) { - struct nx_info *nxi; struct vcmd_net_flags_v0 vc_data; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - nxi = lookup_nx_info(id); - if (!nxi) - return -ESRCH; - vc_data.flagword = nxi->nx_flags; /* special STATE flag handling */ - vc_data.mask = vx_mask_flags(~0UL, nxi->nx_flags, NXF_ONE_TIME); - - put_nx_info(nxi); + vc_data.mask = vs_mask_flags(~0UL, nxi->nx_flags, NXF_ONE_TIME); if (copy_to_user (data, &vc_data, sizeof(vc_data))) return -EFAULT; return 0; } -int vc_set_nflags(uint32_t id, void __user *data) +int vc_set_nflags(struct nx_info *nxi, void __user *data) { - struct nx_info *nxi; struct vcmd_net_flags_v0 vc_data; uint64_t mask, trigger; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; if (copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; - nxi = lookup_nx_info(id); - if (!nxi) - return -ESRCH; - /* special STATE flag handling */ - mask = vx_mask_mask(vc_data.mask, nxi->nx_flags, NXF_ONE_TIME); + mask = vs_mask_mask(vc_data.mask, nxi->nx_flags, NXF_ONE_TIME); trigger = (mask & nxi->nx_flags) ^ (mask & vc_data.flagword); - nxi->nx_flags = vx_mask_flags(nxi->nx_flags, + nxi->nx_flags = vs_mask_flags(nxi->nx_flags, vc_data.flagword, mask); if (trigger & NXF_PERSISTENT) nx_update_persistent(nxi); - put_nx_info(nxi); return 0; } -int vc_get_ncaps(uint32_t id, void __user *data) +int vc_get_ncaps(struct nx_info *nxi, void __user *data) { - struct nx_info *nxi; struct vcmd_net_caps_v0 vc_data; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - nxi = lookup_nx_info(id); - if (!nxi) - return -ESRCH; - vc_data.ncaps = nxi->nx_ncaps; vc_data.cmask = ~0UL; - put_nx_info(nxi); if (copy_to_user (data, &vc_data, sizeof(vc_data))) return -EFAULT; return 0; } -int vc_set_ncaps(uint32_t id, void __user *data) +int vc_set_ncaps(struct nx_info *nxi, void __user *data) { - struct nx_info *nxi; struct vcmd_net_caps_v0 vc_data; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; if (copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; - nxi = lookup_nx_info(id); - if (!nxi) - return -ESRCH; - - nxi->nx_ncaps = vx_mask_flags(nxi->nx_ncaps, + nxi->nx_ncaps = vs_mask_flags(nxi->nx_ncaps, vc_data.ncaps, vc_data.cmask); - put_nx_info(nxi); return 0; }