/* * writing 'C' to /proc/sysrq-trigger is like sysrq-C */ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct ve_struct *cur = get_exec_env(); static int pnum = 10; if (count) { int i, cnt; char c[32]; cnt = min(count, sizeof(c)); if (copy_from_user(c, buf, cnt)) return -EFAULT; for (i = 0; i < cnt && c[i] != '\n'; i++) { if (!ve_is_super(cur)) { if (!pnum) continue; printk("SysRq: CT#%u sent '%c' magic key.\n", cur->veid, c[i]); pnum--; continue; } __handle_sysrq(c[i], NULL, 0); } } return count; }
int cpt_dump_link(struct cpt_context * ctx) { struct net *net = get_exec_env()->ve_netns; struct net_device *dev; cpt_open_section(ctx, CPT_SECT_NET_DEVICE); for_each_netdev(net, dev) { struct cpt_netdev_image v; struct cpt_hwaddr_image hw; loff_t saved_obj; if (dev->netdev_ops->ndo_cpt == NULL) { eprintk_ctx("unsupported netdev %s\n", dev->name); cpt_close_section(ctx); return -EBUSY; } cpt_open_object(NULL, ctx); v.cpt_next = CPT_NULL; v.cpt_object = CPT_OBJ_NET_DEVICE; v.cpt_hdrlen = sizeof(v); v.cpt_content = CPT_CONTENT_ARRAY; v.cpt_index = dev->ifindex; v.cpt_flags = dev->flags; memcpy(v.cpt_name, dev->name, IFNAMSIZ); ctx->write(&v, sizeof(v), ctx); cpt_push_object(&saved_obj, ctx); cpt_open_object(NULL, ctx); dev->netdev_ops->ndo_cpt(dev, &cpt_ops, ctx); /* Dump hardware address */ cpt_open_object(NULL, ctx); hw.cpt_next = CPT_NULL; hw.cpt_object = CPT_OBJ_NET_HWADDR; hw.cpt_hdrlen = sizeof(hw); hw.cpt_content = CPT_CONTENT_VOID; if (dev->dev_addrs.count != 1) { eprintk_ctx("multiple hwaddrs on %s\n", dev->name); return -EINVAL; } BUILD_BUG_ON(sizeof(hw.cpt_dev_addr) != MAX_ADDR_LEN); memcpy(hw.cpt_dev_addr, dev->dev_addr, sizeof(hw.cpt_dev_addr)); ctx->write(&hw, sizeof(hw), ctx); cpt_close_object(ctx); cpt_dump_netstats(dev, ctx); cpt_pop_object(&saved_obj, ctx); cpt_close_object(ctx); } cpt_close_section(ctx); return 0; }
static void sit_cpt(struct net_device *dev, struct cpt_ops *ops, struct cpt_context *ctx) { struct cpt_tunnel_image v; struct ip_tunnel *t; struct sit_net *sitn; t = netdev_priv(dev); sitn = net_generic(get_exec_env()->ve_netns, sit_net_id); BUG_ON(sitn == NULL); v.cpt_next = CPT_NULL; v.cpt_object = CPT_OBJ_NET_IPIP_TUNNEL; v.cpt_hdrlen = sizeof(v); v.cpt_content = CPT_CONTENT_VOID; /* mark fb dev */ v.cpt_tnl_flags = CPT_TUNNEL_SIT; if (dev == sitn->fb_tunnel_dev) v.cpt_tnl_flags |= CPT_TUNNEL_FBDEV; v.cpt_i_flags = t->parms.i_flags; v.cpt_o_flags = t->parms.o_flags; v.cpt_i_key = t->parms.i_key; v.cpt_o_key = t->parms.o_key; BUILD_BUG_ON(sizeof(v.cpt_iphdr) != sizeof(t->parms.iph)); memcpy(&v.cpt_iphdr, &t->parms.iph, sizeof(t->parms.iph)); ops->write(&v, sizeof(v), ctx); }
/* * The higher levels take care of making this non-reentrant (it's * called with bh's disabled). */ static netdev_tx_t loopback_xmit(struct sk_buff *skb, struct net_device *dev) { struct pcpu_lstats *pcpu_lstats, *lb_stats; int len; #ifdef CONFIG_VE if (unlikely(get_exec_env()->disable_net)) { kfree_skb(skb); return 0; } #endif skb_orphan(skb); skb->protocol = eth_type_trans(skb, dev); /* it's OK to use per_cpu_ptr() because BHs are off */ pcpu_lstats = dev->ml_priv; lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); len = skb->len; if (likely(netif_rx(skb) == NET_RX_SUCCESS)) { lb_stats->bytes += len; lb_stats->packets++; } else lb_stats->drops++; return NETDEV_TX_OK; }
static void ve_stop(void *data) { struct ve_struct *ve; int event = VE_EVENT_STOP; if (test_and_clear_bit(VE_REBOOT, &get_exec_env()->flags) && reboot_event) event = VE_EVENT_REBOOT; ve = (struct ve_struct *)data; vzevent_send(event, "%d", ve->veid); }
void vlan_setup(struct net_device *dev) { ether_setup(dev); dev->priv_flags |= IFF_802_1Q_VLAN; dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->tx_queue_len = 0; dev->netdev_ops = &vlan_netdev_ops; dev->destructor = free_netdev; dev->ethtool_ops = &vlan_ethtool_ops; memset(dev->broadcast, 0, ETH_ALEN); if (!ve_is_super(get_exec_env())) dev->features |= NETIF_F_VIRTUAL; }
static int sit_init_net(struct net *net) { int err; struct sit_net *sitn; if (!(get_exec_env()->features & VE_FEATURE_SIT)) return 0; err = -ENOMEM; sitn = kzalloc(sizeof(struct sit_net), GFP_KERNEL); if (sitn == NULL) goto err_alloc; err = net_assign_generic(net, sit_net_id, sitn); if (err < 0) goto err_assign; sitn->tunnels[0] = sitn->tunnels_wc; sitn->tunnels[1] = sitn->tunnels_l; sitn->tunnels[2] = sitn->tunnels_r; sitn->tunnels[3] = sitn->tunnels_r_l; sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", ipip6_tunnel_setup); if (!sitn->fb_tunnel_dev) { err = -ENOMEM; goto err_alloc_dev; } dev_net_set(sitn->fb_tunnel_dev, net); ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); if ((err = register_netdev(sitn->fb_tunnel_dev))) goto err_reg_dev; return 0; err_reg_dev: dev_put(sitn->fb_tunnel_dev); free_netdev(sitn->fb_tunnel_dev); err_alloc_dev: /* nothing */ err_assign: kfree(sitn); err_alloc: return err; }
static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat ) { struct ve_struct *ve = get_exec_env(); generic_fillattr(dentry->d_inode, stat); stat->nlink = glob_proc_root.nlink; if (ve_is_super(ve)) stat->nlink += nr_processes(); #ifdef CONFIG_VE else /* thread count. not really processes count */ stat->nlink += ve->pcounter; /* the same logic as in the proc_getattr */ stat->nlink += ve->proc_root->nlink - 2; #endif return 0; }
static struct kobject *ve_kobj_path_create(char *path) { char *e, *p = path; struct sysfs_dirent *sd, *parent_sd = get_exec_env()->_sysfs_root; struct kobject *k, *pk = NULL; if (*p == '/') p++; while (1) { e = strchr(p, '/'); if (e) *e = '\0'; sd = sysfs_get_dirent(parent_sd, p); if (sd == NULL) { new: k = kobject_create_and_add(p, pk); kobject_put(pk); if (!k) return ERR_PTR(-ENOMEM); } else { if (!(sd->s_flags & SYSFS_DIR)) {
struct file *get_task_file(pid_t pid, int fd) { int err; struct task_struct *tsk; struct files_struct *fs; struct file *file = NULL; err = -ESRCH; read_lock(&tasklist_lock); tsk = find_task_by_pid_ns(pid, get_exec_env()->ve_ns->pid_ns); if (tsk == NULL) { read_unlock(&tasklist_lock); goto out; } get_task_struct(tsk); read_unlock(&tasklist_lock); err = -EINVAL; fs = get_files_struct(tsk); if (fs == NULL) goto out_put; rcu_read_lock(); err = -EBADF; file = fcheck_files(fs, fd); if (file == NULL) goto out_unlock; err = 0; get_file(file); out_unlock: rcu_read_unlock(); put_files_struct(fs); out_put: put_task_struct(tsk); out: return err ? ERR_PTR(err) : file; }
static inline struct vfsmount *ve_devmnt(void) { return get_exec_env()->devtmpfs_mnt; }
int rst_socket_in(struct cpt_sock_image *si, loff_t pos, struct sock *sk, struct cpt_context *ctx) { struct inet_sock *inet = inet_sk(sk); struct net *net = get_exec_env()->ve_ns->net_ns; int err, ret_err = 0; lock_sock(sk); sk->sk_state = si->cpt_state; inet->daddr = si->cpt_daddr; inet->dport = si->cpt_dport; inet->saddr = si->cpt_saddr; inet->rcv_saddr = si->cpt_rcv_saddr; inet->sport = si->cpt_sport; inet->uc_ttl = si->cpt_uc_ttl; inet->tos = si->cpt_tos; inet->cmsg_flags = si->cpt_cmsg_flags; inet->mc_index = si->cpt_mc_index; inet->mc_addr = si->cpt_mc_addr; inet->hdrincl = si->cpt_hdrincl; inet->mc_ttl = si->cpt_mc_ttl; inet->mc_loop = si->cpt_mc_loop; inet->pmtudisc = si->cpt_pmtudisc; inet->recverr = si->cpt_recverr; inet->freebind = si->cpt_freebind; inet->id = si->cpt_idcounter; inet->cork.flags = si->cpt_cork_flags; inet->cork.fragsize = si->cpt_cork_fragsize; inet->cork.length = si->cpt_cork_length; inet->cork.addr = si->cpt_cork_addr; inet->cork.fl.fl4_src = si->cpt_cork_saddr; inet->cork.fl.fl4_dst = si->cpt_cork_daddr; inet->cork.fl.oif = si->cpt_cork_oif; if (inet->cork.fragsize) { if (ip_route_output_key(net, (struct rtable **)&inet->cork.dst, &inet->cork.fl)) { eprintk_ctx("failed to restore cork route\n"); inet->cork.fragsize = 0; } } if (sk->sk_type == SOCK_DGRAM && sk->sk_protocol == IPPROTO_UDP) { struct udp_sock *up = udp_sk(sk); up->pending = si->cpt_udp_pending; up->corkflag = si->cpt_udp_corkflag; up->encap_type = si->cpt_udp_encap; up->len = si->cpt_udp_len; } if (sk->sk_family == AF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); memcpy(&np->saddr, si->cpt_saddr6, 16); memcpy(&np->rcv_saddr, si->cpt_rcv_saddr6, 16); memcpy(&np->daddr, si->cpt_daddr6, 16); np->flow_label = si->cpt_flow_label6; np->frag_size = si->cpt_frag_size6; np->hop_limit = si->cpt_hop_limit6; np->mcast_hops = si->cpt_mcast_hops6; np->mcast_oif = si->cpt_mcast_oif6; np->rxopt.all = si->cpt_rxopt6; np->mc_loop = si->cpt_mc_loop6; np->recverr = si->cpt_recverr6; np->sndflow = si->cpt_sndflow6; np->pmtudisc = si->cpt_pmtudisc6; np->ipv6only = si->cpt_ipv6only6; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) if (si->cpt_mapped) { extern struct inet_connection_sock_af_ops ipv6_mapped; if (sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP) { inet_csk(sk)->icsk_af_ops = &ipv6_mapped; sk->sk_backlog_rcv = tcp_v4_do_rcv; } } #endif } err = restore_queues(sk, si, pos, ctx); if (sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP) { ret_err = err; rst_socket_tcp(si, pos, sk, ctx); } release_sock(sk); return ret_err; }
int rst_restore_ifaddr(struct cpt_context *ctx) { struct net *net = get_exec_env()->ve_netns; int err; loff_t sec = ctx->sections[CPT_SECT_NET_IFADDR]; loff_t endsec; struct cpt_section_hdr h; struct cpt_ifaddr_image di; struct net_device *dev; if (sec == CPT_NULL) return 0; err = ctx->pread(&h, sizeof(h), ctx, sec); if (err) return err; if (h.cpt_section != CPT_SECT_NET_IFADDR || h.cpt_hdrlen < sizeof(h)) return -EINVAL; endsec = sec + h.cpt_next; sec += h.cpt_hdrlen; while (sec < endsec) { int cindex = -1; int err; err = rst_get_object(CPT_OBJ_NET_IFADDR, sec, &di, ctx); if (err) return err; cindex = di.cpt_index; rtnl_lock(); dev = __dev_get_by_index(net, cindex); if (dev && di.cpt_family == AF_INET) { struct in_device *in_dev; struct in_ifaddr *ifa; if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) in_dev = inetdev_init(dev); ifa = inet_alloc_ifa(); if (ifa) { ifa->ifa_local = di.cpt_address[0]; ifa->ifa_address = di.cpt_peer[0]; ifa->ifa_broadcast = di.cpt_broadcast[0]; ifa->ifa_prefixlen = di.cpt_masklen; ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen); ifa->ifa_flags = di.cpt_flags; ifa->ifa_scope = di.cpt_scope; memcpy(ifa->ifa_label, di.cpt_label, IFNAMSIZ); in_dev_hold(in_dev); ifa->ifa_dev = in_dev; err = inet_insert_ifa(ifa); if (err && err != -EEXIST) { rtnl_unlock(); eprintk_ctx("add ifaddr err %d for %d %s\n", err, di.cpt_index, di.cpt_label); return err; } } #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) } else if (dev && di.cpt_family == AF_INET6) { __u32 prefered_lft; __u32 valid_lft; struct net *net = get_exec_env()->ve_ns->net_ns; prefered_lft = (di.cpt_flags & IFA_F_DEPRECATED) ? 0 : di.cpt_prefered_lft; valid_lft = (di.cpt_flags & IFA_F_PERMANENT) ? 0xFFFFFFFF : di.cpt_valid_lft; err = inet6_addr_add(net, dev->ifindex, (struct in6_addr *)di.cpt_address, di.cpt_masklen, 0, prefered_lft, valid_lft); if (err && err != -EEXIST) { rtnl_unlock(); eprintk_ctx("add ifaddr err %d for %d %s\n", err, di.cpt_index, di.cpt_label); return err; } #endif } else { rtnl_unlock(); eprintk_ctx("unknown ifaddr 2 for %d\n", di.cpt_index); return -EINVAL; } rtnl_unlock(); sec += di.cpt_next; } return 0; }
int rst_restore_netdev(struct cpt_context *ctx) { struct net *net = get_exec_env()->ve_netns; int err; loff_t sec = ctx->sections[CPT_SECT_NET_DEVICE]; loff_t endsec; struct cpt_section_hdr h; struct cpt_netdev_image di; struct net_device *dev; get_exec_env()->disable_net = 1; if (sec == CPT_NULL) return 0; err = ctx->pread(&h, sizeof(h), ctx, sec); if (err) return err; if (h.cpt_section != CPT_SECT_NET_DEVICE || h.cpt_hdrlen < sizeof(h)) return -EINVAL; endsec = sec + h.cpt_next; sec += h.cpt_hdrlen; while (sec < endsec) { loff_t pos; struct net_device *dev_new; struct netdev_rst *ops; err = rst_get_object(CPT_OBJ_NET_DEVICE, sec, &di, ctx); if (err) return err; rtnl_lock(); pos = sec + di.cpt_hdrlen; if (di.cpt_next > sizeof(di)) { struct cpt_object_hdr hdr; err = ctx->pread(&hdr, sizeof(struct cpt_object_hdr), ctx, sec + di.cpt_hdrlen); if (err) goto out; ops = NULL; while (1) { ops = netdev_find_rst(hdr.cpt_object, ops); if (ops == NULL) break; err = ops->ndo_rst(sec, &di, &rst_ops, ctx); if (!err) { pos += hdr.cpt_next; break; } else if (err < 0) { eprintk_ctx("netdev %d rst failed %d\n", hdr.cpt_object, err); goto out; } } } dev = __dev_get_by_name(net, di.cpt_name); if (dev) { if (dev->ifindex != di.cpt_index) { dev_new = __dev_get_by_index(net, di.cpt_index); if (!dev_new) { write_lock_bh(&dev_base_lock); hlist_del(&dev->index_hlist); if (dev->iflink == dev->ifindex) dev->iflink = di.cpt_index; dev->ifindex = di.cpt_index; hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); write_unlock_bh(&dev_base_lock); } else { write_lock_bh(&dev_base_lock); hlist_del(&dev->index_hlist); hlist_del(&dev_new->index_hlist); if (dev_new->iflink == dev_new->ifindex) dev_new->iflink = dev->ifindex; dev_new->ifindex = dev->ifindex; if (dev->iflink == dev->ifindex) dev->iflink = di.cpt_index; dev->ifindex = di.cpt_index; hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); hlist_add_head(&dev_new->index_hlist, dev_index_hash(net, dev_new->ifindex)); write_unlock_bh(&dev_base_lock); } } if (di.cpt_flags^dev->flags) { err = dev_change_flags(dev, di.cpt_flags); if (err) eprintk_ctx("dev_change_flags err: %d\n", err); } while (pos < sec + di.cpt_next) { struct cpt_object_hdr hdr; err = ctx->pread(&hdr, sizeof(struct cpt_object_hdr), ctx, pos); if (err) goto out; if (hdr.cpt_object == CPT_OBJ_NET_HWADDR) { /* Restore hardware address */ struct cpt_hwaddr_image hw; err = rst_get_object(CPT_OBJ_NET_HWADDR, pos, &hw, ctx); if (err) goto out; BUILD_BUG_ON(sizeof(hw.cpt_dev_addr) != MAX_ADDR_LEN); memcpy(dev->dev_addr, hw.cpt_dev_addr, sizeof(hw.cpt_dev_addr)); } else if (hdr.cpt_object == CPT_OBJ_NET_STATS) { err = rst_restore_netstats(pos, dev, ctx); if (err) { eprintk_ctx("rst stats %s: %d\n", di.cpt_name, err); goto out; } } pos += hdr.cpt_next; } } else { eprintk_ctx("unknown interface 2 %s\n", di.cpt_name); } rtnl_unlock(); sec += di.cpt_next; } return 0; out: rtnl_unlock(); return err; }
static int uts_arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct uts_namespace *uts_ns = current->nsproxy->uts_ns; struct ve_struct *ve = get_exec_env(); int i, n1, n2, n3, new_version; struct page **new_pages, **p; /* * For node or in case we've not changed UTS simply * map preallocated original vDSO. * * In turn if we already allocated one for this UTS * simply reuse it. It improves speed significantly. */ if (uts_ns == &init_uts_ns) goto map_init_uts; /* * Dirty lockless hack. Strictly speaking * we need to return @p here if it's non-nil, * but since there only one trasition possible * { =0 ; !=0 } we simply return @uts_ns->vdso.pages */ p = ACCESS_ONCE(uts_ns->vdso.pages); smp_read_barrier_depends(); if (p) goto map_uts; if (sscanf(uts_ns->name.release, "%d.%d.%d", &n1, &n2, &n3) == 3) { /* * If there were no changes on version simply reuse * preallocated one. */ new_version = KERNEL_VERSION(n1, n2, n3); if (new_version == LINUX_VERSION_CODE) goto map_init_uts; } else { /* * If admin is passed malformed string here * lets warn him once but continue working * not using vDSO virtualization at all. It's * better than walk out with error. */ pr_warn_once("Wrong release uts name format detected." " Ignoring vDSO virtualization.\n"); goto map_init_uts; } mutex_lock(&vdso_mutex); if (uts_ns->vdso.pages) { mutex_unlock(&vdso_mutex); goto map_uts; } uts_ns->vdso.nr_pages = init_uts_ns.vdso.nr_pages; uts_ns->vdso.size = init_uts_ns.vdso.size; uts_ns->vdso.version_off= init_uts_ns.vdso.version_off; new_pages = kmalloc(sizeof(struct page *) * init_uts_ns.vdso.nr_pages, GFP_KERNEL); if (!new_pages) { pr_err("Can't allocate vDSO pages array for VE %d\n", ve->veid); goto out_unlock; } for (i = 0; i < uts_ns->vdso.nr_pages; i++) { struct page *p = alloc_page(GFP_KERNEL); if (!p) { pr_err("Can't allocate page for VE %d\n", ve->veid); for (; i > 0; i--) put_page(new_pages[i - 1]); kfree(new_pages); goto out_unlock; } new_pages[i] = p; copy_page(page_address(p), page_address(init_uts_ns.vdso.pages[i])); } uts_ns->vdso.addr = vmap(new_pages, uts_ns->vdso.nr_pages, 0, PAGE_KERNEL); if (!uts_ns->vdso.addr) { pr_err("Can't map vDSO pages for VE %d\n", ve->veid); for (i = 0; i < uts_ns->vdso.nr_pages; i++) put_page(new_pages[i]); kfree(new_pages); goto out_unlock; } *((int *)(uts_ns->vdso.addr + uts_ns->vdso.version_off)) = new_version; smp_wmb(); uts_ns->vdso.pages = new_pages; mutex_unlock(&vdso_mutex); pr_debug("vDSO version transition %d -> %d for VE %d\n", LINUX_VERSION_CODE, new_version, ve->veid); map_uts: return setup_additional_pages(bprm, uses_interp, uts_ns->vdso.pages, uts_ns->vdso.size); map_init_uts: return setup_additional_pages(bprm, uses_interp, init_uts_ns.vdso.pages, init_uts_ns.vdso.size); out_unlock: mutex_unlock(&vdso_mutex); return -ENOMEM; }
static int sit_rst(loff_t start, struct cpt_netdev_image *di, struct rst_ops *ops, struct cpt_context *ctx) { int err = -ENODEV; struct cpt_tunnel_image v; struct net_device *dev; struct ip_tunnel *t; loff_t pos; int fbdev; struct sit_net *sitn; sitn = net_generic(get_exec_env()->ve_netns, sit_net_id); if (sitn == NULL) return -EOPNOTSUPP; pos = start + di->cpt_hdrlen; err = ops->get_object(CPT_OBJ_NET_IPIP_TUNNEL, pos, &v, sizeof(v), ctx); if (err) return err; /* some sanity */ if (v.cpt_content != CPT_CONTENT_VOID) return -EINVAL; if (!(v.cpt_tnl_flags & CPT_TUNNEL_SIT)) return 1; if (v.cpt_tnl_flags & CPT_TUNNEL_FBDEV) { fbdev = 1; err = 0; dev = sitn->fb_tunnel_dev; } else { fbdev = 0; err = -ENOMEM; dev = alloc_netdev(sizeof(struct ip_tunnel), di->cpt_name, ipip6_tunnel_setup); if (!dev) goto out; } t = netdev_priv(dev); t->parms.i_flags = v.cpt_i_flags; t->parms.o_flags = v.cpt_o_flags; t->parms.i_key = v.cpt_i_key; t->parms.o_key = v.cpt_o_key; BUILD_BUG_ON(sizeof(v.cpt_iphdr) != sizeof(t->parms.iph)); memcpy(&t->parms.iph, &v.cpt_iphdr, sizeof(t->parms.iph)); if (!fbdev) { ipip6_tunnel_init(dev); err = register_netdevice(dev); if (err) { free_netdev(dev); goto out; } dev_hold(dev); ipip6_tunnel_link(sitn, t); } out: return err; }
int cpt_suspend_network(struct cpt_context *ctx) { get_exec_env()->disable_net = 1; synchronize_net(); return 0; }
int cpt_dump_ifaddr(struct cpt_context * ctx) { struct net *net = get_exec_env()->ve_netns; struct net_device *dev; cpt_open_section(ctx, CPT_SECT_NET_IFADDR); for_each_netdev(net, dev) { struct in_device *idev = in_dev_get(dev); struct in_ifaddr *ifa; if (!idev) continue; for (ifa = idev->ifa_list; ifa; ifa = ifa->ifa_next) { struct cpt_ifaddr_image v; cpt_open_object(NULL, ctx); v.cpt_next = CPT_NULL; v.cpt_object = CPT_OBJ_NET_IFADDR; v.cpt_hdrlen = sizeof(v); v.cpt_content = CPT_CONTENT_VOID; v.cpt_index = dev->ifindex; v.cpt_family = AF_INET; v.cpt_masklen = ifa->ifa_prefixlen; v.cpt_flags = ifa->ifa_flags; v.cpt_scope = ifa->ifa_scope; memset(&v.cpt_address, 0, sizeof(v.cpt_address)); memset(&v.cpt_peer, 0, sizeof(v.cpt_peer)); memset(&v.cpt_broadcast, 0, sizeof(v.cpt_broadcast)); v.cpt_address[0] = ifa->ifa_local; v.cpt_peer[0] = ifa->ifa_address; v.cpt_broadcast[0] = ifa->ifa_broadcast; memcpy(v.cpt_label, ifa->ifa_label, IFNAMSIZ); ctx->write(&v, sizeof(v), ctx); cpt_close_object(ctx); } in_dev_put(idev); } #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) for_each_netdev(net, dev) { struct inet6_dev *idev = in6_dev_get(dev); struct inet6_ifaddr *ifa; if (!idev) continue; for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) { struct cpt_ifaddr_image v; if (dev == net->loopback_dev && ifa->prefix_len == 128 && ifa->addr.s6_addr32[0] == 0 && ifa->addr.s6_addr32[1] == 0 && ifa->addr.s6_addr32[2] == 0 && ifa->addr.s6_addr32[3] == htonl(1)) continue; cpt_open_object(NULL, ctx); v.cpt_next = CPT_NULL; v.cpt_object = CPT_OBJ_NET_IFADDR; v.cpt_hdrlen = sizeof(v); v.cpt_content = CPT_CONTENT_VOID; v.cpt_index = dev->ifindex; v.cpt_family = AF_INET6; v.cpt_masklen = ifa->prefix_len; v.cpt_flags = ifa->flags; v.cpt_scope = ifa->scope; v.cpt_valid_lft = ifa->valid_lft; v.cpt_prefered_lft = ifa->prefered_lft; memcpy(&v.cpt_address, &ifa->addr, 16); memcpy(&v.cpt_peer, &ifa->addr, 16); memset(&v.cpt_broadcast, 0, sizeof(v.cpt_broadcast)); memcpy(v.cpt_label, dev->name, IFNAMSIZ); ctx->write(&v, sizeof(v), ctx); cpt_close_object(ctx); } in6_dev_put(idev); } #endif cpt_close_section(ctx); return 0; }
static int cpt_dump_iptables(struct cpt_context * ctx) { int err = 0; #ifdef CONFIG_VE_IPTABLES int pid; int pfd[2]; struct file *f; struct cpt_object_hdr v; char buf[16]; loff_t pos; int n; int status; mm_segment_t oldfs; sigset_t ignore, blocked; struct args_t args; struct ve_struct *oldenv; if (!(get_exec_env()->_iptables_modules & VE_IP_IPTABLES_MOD)) return 0; err = sc_pipe(pfd); if (err < 0) { eprintk_ctx("sc_pipe: %d\n", err); return err; } args.pfd = pfd; args.veid = VEID(get_exec_env()); ignore.sig[0] = CPT_SIG_IGNORE_MASK; sigprocmask(SIG_BLOCK, &ignore, &blocked); oldenv = set_exec_env(get_ve0()); err = pid = local_kernel_thread(dumpfn, (void*)&args, SIGCHLD | CLONE_VFORK, 0); set_exec_env(oldenv); if (err < 0) { eprintk_ctx("local_kernel_thread: %d\n", err); goto out; } f = fget(pfd[0]); sc_close(pfd[1]); sc_close(pfd[0]); cpt_open_section(ctx, CPT_SECT_NET_IPTABLES); cpt_open_object(NULL, ctx); v.cpt_next = CPT_NULL; v.cpt_object = CPT_OBJ_NAME; v.cpt_hdrlen = sizeof(v); v.cpt_content = CPT_CONTENT_NAME; ctx->write(&v, sizeof(v), ctx); pos = ctx->file->f_pos; do { oldfs = get_fs(); set_fs(KERNEL_DS); n = f->f_op->read(f, buf, sizeof(buf), &f->f_pos); set_fs(oldfs); if (n > 0) ctx->write(buf, n, ctx); } while (n > 0); if (n < 0) eprintk_ctx("read: %d\n", n); fput(f); oldfs = get_fs(); set_fs(KERNEL_DS); if ((err = sc_waitx(pid, 0, &status)) < 0) eprintk_ctx("wait4: %d\n", err); else if ((status & 0x7f) == 0) { err = (status & 0xff00) >> 8; if (err != 0) { eprintk_ctx("iptables-save exited with %d\n", err); err = -EINVAL; } } else {
/** * kthread_create_ve - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start * it. See also kthread_run(), kthread_create_on_cpu(). * * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which noone will call kthread_stop(), or * return when 'kthread_should_stop()' is true (which means * kthread_stop() has been called). The return value should be zero * or a negative error number; it will be passed to kthread_stop(). * * Returns a task_struct or ERR_PTR(-ENOMEM). */ struct task_struct *kthread_create_ve(struct ve_struct *ve, int (*threadfn)(void *data), void *data, const char namefmt[], ...) { struct kthread_create_info create; struct ve_struct *old_ve; old_ve = set_exec_env(ve); create.threadfn = threadfn; create.data = data; init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); set_cpus_allowed_ptr(create.result, cpu_all_mask); } set_exec_env(old_ve); return create.result; } EXPORT_SYMBOL(kthread_create_ve); /** * kthread_stop - stop a thread created by kthread_create(). * @k: thread created by kthread_create(). * * Sets kthread_should_stop() for @k to return true, wakes it, and * waits for it to exit. This can also be called after kthread_create() * instead of calling wake_up_process(): the thread will exit without * calling threadfn(). * * If threadfn() may call do_exit() itself, the caller must ensure * task_struct can't go away. * * Returns the result of threadfn(), or %-EINTR if wake_up_process() * was never called. */ int kthread_stop(struct task_struct *k) { struct kthread *kthread; int ret; trace_sched_kthread_stop(k); get_task_struct(k); kthread = to_kthread(k); barrier(); /* it might have exited */ if (k->vfork_done != NULL) { kthread->should_stop = 1; wake_up_process(k); wait_for_completion(&kthread->exited); } ret = k->exit_code; put_task_struct(k); trace_sched_kthread_stop_ret(ret); return ret; } EXPORT_SYMBOL(kthread_stop); int kthreadd(void *data) { struct task_struct *tsk = current; struct kthreadd_create_info *kcreate; struct kthread self; int rc; self.should_stop = 0; kcreate = (struct kthreadd_create_info *) data; if (kcreate) { daemonize("kthreadd/%d", get_exec_env()->veid); kcreate->result = current; set_fs(KERNEL_DS); init_completion(&self.exited); current->vfork_done = &self.exited; } else set_task_comm(tsk, "kthreadd"); /* Setup a clean context for our children to inherit. */ ignore_signals(tsk); set_cpus_allowed_ptr(tsk, cpu_all_mask); set_mems_allowed(node_states[N_HIGH_MEMORY]); current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG; if (kcreate) complete(&kcreate->done); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&kthread_create_list)) { if (self.should_stop) break; else schedule(); } __set_current_state(TASK_RUNNING); spin_lock(&kthread_create_lock); while (!list_empty(&kthread_create_list)) { struct kthread_create_info *create; create = list_entry(kthread_create_list.next, struct kthread_create_info, list); list_del_init(&create->list); spin_unlock(&kthread_create_lock); create_kthread(create); spin_lock(&kthread_create_lock); } spin_unlock(&kthread_create_lock); } do { clear_thread_flag(TIF_SIGPENDING); rc = sys_wait4(-1, NULL, __WALL, NULL); } while (rc != -ECHILD); do_exit(0); } int kthreadd_create() { struct kthreadd_create_info create; int ret; struct ve_struct *ve = get_exec_env(); BUG_ON(ve->_kthreadd_task); INIT_LIST_HEAD(&ve->_kthread_create_list); init_completion(&create.done); ret = kernel_thread(kthreadd, (void *) &create, CLONE_FS); if (ret < 0) { return ret; } wait_for_completion(&create.done); ve->_kthreadd_task = create.result; return 0; } EXPORT_SYMBOL(kthreadd_create); void kthreadd_stop(struct ve_struct *ve) { struct kthread *kthread; int ret; struct task_struct *k; if (!ve->_kthreadd_task) return; k = ve->_kthreadd_task; trace_sched_kthread_stop(k); get_task_struct(k); BUG_ON(!k->vfork_done); kthread = container_of(k->vfork_done, struct kthread, exited); kthread->should_stop = 1; wake_up_process(k); wait_for_completion(&kthread->exited); ret = k->exit_code; put_task_struct(k); trace_sched_kthread_stop_ret(ret); } EXPORT_SYMBOL(kthreadd_stop);
static int show_cpuinfo(struct seq_file *m, void *v) { struct cpuinfo_x86 *c = v; unsigned int cpu; int is_super = ve_is_super(get_exec_env()); int i; cpu = c->cpu_index; seq_printf(m, "processor\t: %u\n" "vendor_id\t: %s\n" "cpu family\t: %d\n" "model\t\t: %u\n" "model name\t: %s\n", cpu, c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown", c->x86, c->x86_model, c->x86_model_id[0] ? c->x86_model_id : "unknown"); if (c->x86_mask || c->cpuid_level >= 0) seq_printf(m, "stepping\t: %d\n", c->x86_mask); else seq_printf(m, "stepping\t: unknown\n"); if (c->microcode) seq_printf(m, "microcode\t: 0x%x\n", c->microcode); if (cpu_has(c, X86_FEATURE_TSC)) { unsigned int freq = cpufreq_quick_get(cpu); if (!freq) freq = cpu_khz; freq = sched_cpulimit_scale_cpufreq(freq); seq_printf(m, "cpu MHz\t\t: %u.%03u\n", freq / 1000, (freq % 1000)); } /* Cache size */ if (c->x86_cache_size >= 0) seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); show_cpuinfo_core(m, c, cpu); show_cpuinfo_misc(m, c); seq_printf(m, "flags\t\t:"); for (i = 0; i < 32*NCAPINTS; i++) if (x86_cap_flags[i] != NULL && ((is_super && cpu_has(c, i)) || (!is_super && test_bit(i, (unsigned long *) &per_cpu(cpu_flags, cpu))))) seq_printf(m, " %s", x86_cap_flags[i]); seq_printf(m, "\nbogomips\t: %lu.%02lu\n", c->loops_per_jiffy/(500000/HZ), (c->loops_per_jiffy/(5000/HZ)) % 100); #ifdef CONFIG_X86_64 if (c->x86_tlbsize > 0) seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize); #endif seq_printf(m, "clflush size\t: %u\n", c->x86_clflush_size); seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment); seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n", c->x86_phys_bits, c->x86_virt_bits); seq_printf(m, "power management:"); for (i = 0; i < 32; i++) { if (c->x86_power & (1 << i)) { if (i < ARRAY_SIZE(x86_power_flags) && x86_power_flags[i]) seq_printf(m, "%s%s", x86_power_flags[i][0] ? " " : "", x86_power_flags[i]); else seq_printf(m, " [%d]", i); } } seq_printf(m, "\n\n"); return 0; }