#include #include #include #include #include #include #include #include #include #include "lve_internal.h" #include "lve_debug.h" #include "light_ve.h" #include "resource.h" #include "os/cgroup_lib.h" #include "lve_os_compat.h" #ifdef HAVE_PROC_OPS #define proc_ops(name,open,read,write,seek,release) \ static const struct proc_ops name = { \ .proc_flags = PROC_ENTRY_PERMANENT, \ .proc_open = open, \ .proc_read = read, \ .proc_write = write, \ .proc_lseek = seek, \ .proc_release = release, \ }; #else #define proc_ops(name,_open,_read,_write,_seek,_release) \ static const struct file_operations name = { \ .owner = THIS_MODULE, \ .open = _open, \ .read = _read, \ .write = _write, \ .llseek = _seek, \ .release = _release, \ }; #endif static int lvp_single_release(struct inode *inode, struct file *file) { struct lvp_ve_private *lvp = PDE_DATA(inode); int rc; rc = single_release(inode, file); lvp_put(lvp); return rc; } static int lve_single_release(struct inode *inode, struct file *file) { struct light_ve *lve = PDE_DATA(inode); int rc; rc = single_release(inode, file); light_ve_put(lve); return rc; } /************************ list *********************************/ static void lve_limits_hdr(struct seq_file *m) { seq_printf(m, "\tlCPU\tlCPUW\tnCPU"); seq_printf(m, "\tlEP\tlNPROC"); seq_printf(m, "\tlMEM\tlMEMPHY"); seq_printf(m, "\tlIO\tlIOPS"); seq_printf(m, "\tlNETO\tlNETI"); } static void lve_limits_print(struct seq_file *m, lve_limits_t limits) { seq_printf(m, "\t%u\t%u\t%u", limits[LIM_CPU], limits[LIM_CPU_WEIGHT], limits[LIM_CPUS]); seq_printf(m, "\t%u\t%u", limits[LIM_ENTER], limits[LIM_NPROC]); seq_printf(m, "\t%u\t%u", limits[LIM_MEMORY], limits[LIM_MEMORY_PHY]); seq_printf(m, "\t%u\t%u", limits[LIM_IO], limits[LIM_IOPS]); } static void lve_stat_hdr_show(struct seq_file *m, struct lvp_ve_private *lvp) { seq_printf(m, "10:LVE"); lve_limits_hdr(m); seq_printf(m, "\tEP"); seq_printf(m, "\tCPU\tMEM\tIO"); seq_printf(m, "\tfMEM\tfEP"); seq_printf(m, "\tMEMPHY\tfMEMPHY\tNPROC\tfNPROC"); seq_printf(m, "\tIOPS"); seq_printf(m, "\tNETO\tNETI"); seq_printf(m, "\n"); seq_printf(m, "%u,%u\t", lvp->lvp_id, 0); lve_limits_print(m, lvp->lvp_def_limits); seq_printf(m, "\t"LPU64"\t"LPU64, 0ULL, 0ULL); /** Usage */ seq_printf(m, "\t"LPU64, 0ULL); seq_printf(m, "\t"LPU64"\t"LPU64"\t"LPU64, 0ULL, 0ULL, 0ULL); seq_printf(m, "\t"LPU64"\t"LPU64, 0ULL, 0ULL); seq_printf(m, "\t"LPU64"\t"LPU64, 0ULL, 0ULL); seq_printf(m, "\t"LPU64"\t"LPU64, 0ULL, 0ULL); seq_printf(m, "\t"LPU64, 0ULL); seq_printf(m, "\t"LPU64"\t"LPU64, 0ULL, 0ULL); seq_printf(m, "\n"); } static void lve_stat_show(struct seq_file *m, struct light_ve *lve) { struct lve_usage usage; lve_resource_usage(lve, &usage); /* XXX read long always atomic */ seq_printf(m, "%u,%u", lve->lve_lvp->lvp_id, lve->lve_id); lve_limits_print(m, lve->lve_limits); seq_printf(m, "\t"LPU64"\t"LPU64, (uint64_t)atomic64_read(&lve->lve_net.ln_stats.out_limit), (uint64_t)atomic64_read(&lve->lve_net.ln_stats.in_limit)); /** Usage */ seq_printf(m, "\t"LPU64, usage.data[RES_ENTER].data); seq_printf(m, "\t"LPU64"\t"LPU64"\t"LPU64, usage.data[RES_CPU].data, usage.data[RES_MEM].data, usage.data[RES_IO].data); seq_printf(m, "\t"LPU64"\t"LPU64, usage.data[RES_MEM].fail, usage.data[RES_ENTER].fail); seq_printf(m, "\t"LPU64"\t"LPU64, usage.data[RES_MEM_PHY].data, usage.data[RES_MEM_PHY].fail); seq_printf(m, "\t"LPU64"\t"LPU64, usage.data[RES_NPROC].data, usage.data[RES_NPROC].fail); seq_printf(m, "\t"LPU64, usage.data[RES_IOPS].data); seq_printf(m, "\t"LPU64"\t"LPU64, (uint64_t)atomic64_read(&lve->lve_net.ln_stats.out_total), (uint64_t)atomic64_read(&lve->lve_net.ln_stats.in_total)); seq_printf(m, "\n"); } static void lve_net_stat_show(struct seq_file *m, struct light_ve *lve) { seq_printf(m, "traf: "); lve_net_traf_show(m, lve); seq_printf(m, "\n"); lve_net_port_show(m, lve); } static void *list_usage_start(struct seq_file *m, loff_t *pos) { struct lvp_ve_private *lvp = m->private; return seq_list_start_head(&lvp->lvp_lve_list, *pos); } static void list_usage_stop(struct seq_file *m, void *v) { } static void * list_usage_next(struct seq_file *m, void *v, loff_t *pos) { struct lvp_ve_private *lvp = m->private; return seq_list_next(v, &lvp->lvp_lve_list, pos); } static int list_show(struct seq_file *m, void *v) { struct lvp_ve_private *lvp = m->private; struct light_ve *lve; if (v == &lvp->lvp_lve_list) { lve_stat_hdr_show(m, lvp); return 0; } lve = list_entry(v, struct light_ve, lve_link); lve_stat_show(m, lve); return 0; } static ssize_t list_usage_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { struct seq_file *m = file->private_data; struct lvp_ve_private *lvp __maybe_unused = m->private; ssize_t rsize; /* * We need to lock here to guarantee that a large * single read provides consistent data, which we * cannot do if we unlock in ->stop. * * Small chunk readers might read trash anyway... */ down_read(&lvp_tree_lock(lvp)); rsize = seq_read(file, buf, size, ppos); up_read(&lvp_tree_lock(lvp)); return rsize; } static struct seq_operations list_ops = { .start = list_usage_start, .next = list_usage_next, .stop = list_usage_stop, .show = list_show, }; static int lve_list_open(struct inode *inode, struct file *file) { int rc; struct seq_file *m; rc = seq_open(file, &list_ops); if (rc) return rc; m = file->private_data; m->private = PDE_DATA(inode); return 0; } proc_ops(lve_list_fops, lve_list_open, list_usage_read, NULL, seq_lseek, seq_release); /**************** list end ***************************/ static int usage_show(struct seq_file *m, void *v) { struct light_ve *lve; struct lve_usage usage; struct lvp_ve_private *lvp = m->private; if (v == &lvp->lvp_lve_list) { seq_printf(m, "LAST RESET: %lu\n", lvp->lvp_last_reset); seq_printf(m, "LVE\tfMEM\tfEP\tCPU\n"); return 0; } lve = list_entry(v, struct light_ve, lve_link); lve_resource_usage(lve, &usage); seq_printf(m, "%u,%u\t%lu\t%ld\t"LPU64"\n", lve->lve_lvp->lvp_id, lve->lve_id, (unsigned long)0, lve->lve_stats.st_err_enters, usage.data[RES_CPU].data); return 0; } #define LVE_CLEAR_CMD "clear" static ssize_t lve_usage_write(struct file *file, const char __user *data, size_t count, loff_t *off) { char d[sizeof LVE_CLEAR_CMD + 1]; struct light_ve *lve; struct seq_file *m = file->private_data; struct lvp_ve_private *lvp = m->private; int rc; if (!data || count < (sizeof(LVE_CLEAR_CMD) - 1) || *off) return -EINVAL; memset(d, 0, sizeof d); rc = copy_from_user(d, data, (sizeof(LVE_CLEAR_CMD) - 1)); if (rc) return rc; if (strcmp(d, LVE_CLEAR_CMD)) return -ENOSYS; down_read(&lvp_tree_lock(lvp)); list_for_each_entry(lve, &lvp->lvp_lve_list, lve_link) { rc = os_resource_usage_clear(lve_private(lve)); if (rc) LVE_WARN("failed to clear resource usage for lve=%u", lve->lve_id); spin_lock(&lve->lve_stats.enter_lock); lve->lve_stats.st_err_enters = 0; spin_unlock(&lve->lve_stats.enter_lock); /** XXX mem fault reset*/ } up_read(&lvp_tree_lock(lvp)); lvp->lvp_last_reset = ktime_get_seconds(); return count; } static struct seq_operations usage_ops = { .start = list_usage_start, .next = list_usage_next, .stop = list_usage_stop, .show = usage_show, }; static int lve_usage_open(struct inode *inode, struct file *file) { int rc; struct seq_file *m; rc = seq_open(file, &usage_ops); if (rc) return rc; m = file->private_data; m->private = PDE_DATA(inode); return 0; } proc_ops(lve_usage_fops, lve_usage_open, list_usage_read, lve_usage_write, seq_lseek, seq_release); static const char *facilities[] = { [LVE_DEBUG_FAC_DBG] = "debug", [LVE_DEBUG_FAC_WARN] = "warning", [LVE_DEBUG_FAC_ERR] = "error" }; static ssize_t lve_debug_write(struct file *file, const char __user *data, size_t count, loff_t *off) { static DEFINE_SPINLOCK(update_lock); char str[50], *pstr = str; int rc, i; unsigned newmask = 0, op = 0; if (!data || count > (sizeof(str) - 1) || *off) return -EINVAL; rc = copy_from_user(str, data, count); if (rc) return -EFAULT; str[count] = '\0'; /* add subsystems to the list */ if (str[0] == '+') { op = +1; pstr++; } /* remove subsystems from the list */ if (str[0] == '-') { op = -1; pstr++; } while (*pstr) { char *lstr; while (*pstr == ' ' || *pstr == '\t' || *pstr == '\n') pstr++; if (!*pstr) break; lstr = pstr; while (*lstr != ' ' && *lstr != '\t' && *lstr != '\n' && *lstr) lstr++; for (i = 0; i < ARRAY_SIZE(facilities); i++) { if (strlen(facilities[i]) == (lstr - pstr) && !strncmp(facilities[i], pstr, lstr - pstr)) { newmask |= (1 << i); break; } } if (i == ARRAY_SIZE(facilities)) return -EINVAL; pstr = lstr; } spin_lock(&update_lock); switch (op) { case -1: lve_debug_mask &= ~newmask; break; case 0: lve_debug_mask = newmask; break; case +1: lve_debug_mask |= newmask; break; default: BUG(); } spin_unlock(&update_lock); return count; } static int debug_show(struct seq_file *m, void *v) { unsigned long mask = lve_debug_mask, i; for (i = 0; i < ARRAY_SIZE(facilities); i++, mask >>= 1) { if (mask & 1) { seq_puts(m, facilities[i]); if (mask > 1) seq_putc(m, ' '); } } seq_putc(m, '\n'); return 0; } static int lve_debug_open(struct inode *inode, struct file *file) { int ret; ret = single_open(file, debug_show, NULL); if (ret) return ret; return 0; } proc_ops(lve_debug_fops, lve_debug_open, seq_read, lve_debug_write, seq_lseek, single_release); static ssize_t lve_fail_write(struct file *file, const char __user *data, size_t count, loff_t *off) { char str[50], *ptr; int rc; unsigned long new_value; if (!data || count > (sizeof(str) - 1) || *off) return -EINVAL; rc = copy_from_user(str, data, count); if (rc) return -EFAULT; str[count] = '\0'; new_value = simple_strtoul(str, &ptr, 0); if (ptr == str) return -EINVAL; fail_value = new_value; return count; } static int fail_show(struct seq_file *m, void *v) { seq_printf(m, "0x%lx\n", fail_value); return 0; } static int lve_fail_open(struct inode *inode, struct file *file) { int ret; ret = single_open(file, fail_show, NULL); if (ret) return ret; return 0; } proc_ops(lve_fail_fops, lve_fail_open, seq_read, lve_fail_write, seq_lseek, single_release); static ssize_t lve_enter_write(struct file *file, const char __user *data, size_t count, loff_t *off) { char str[50]; int rc; struct seq_file *m = file->private_data; struct lvp_ve_private *lvp = m->private; if (!data || count > (sizeof(str) - 1) || *off) return -EINVAL; rc = copy_from_user(str, data, count); if (rc) return -EFAULT; str[count] = '\0'; if (str[0] == '+') { rc = lve_exec_add_file(lvp, &str[1]); if (rc) return rc; } else if (str[0] == '-') { rc = lve_exec_del_file(lvp, &str[1]); if (rc) return rc; } else { return -EINVAL; } return count; } static int lve_enter_show(struct seq_file *m, void *v) { struct lve_exec_entry *e; char pathname[256], *rpath; struct lvp_ve_private *lvp = m->private; read_lock(&lvp->lvp_exec_lock); list_for_each_entry(e, &lvp->lvp_exec_entries, list) { rpath = d_path(&e->path, pathname, sizeof(pathname)); seq_printf(m, "%s\n", rpath); } read_unlock(&lvp->lvp_exec_lock); return 0; } static int lve_enter_open(struct inode *inode, struct file *file) { lvp_get(PDE_DATA(inode)); return single_open(file, lve_enter_show, PDE_DATA(inode)); } proc_ops(lve_enter_fops, lve_enter_open, seq_read, lve_enter_write, seq_lseek, lvp_single_release); /* XXXXX copy paste from kernel */ #ifdef HAVE_TASK_STAT struct sched_entity_stats { struct sched_entity se; struct sched_statistics stats; } __no_randomize_layout; #ifdef CONFIG_FAIR_GROUP_SCHED /* An entity is a task if it doesn't "own" a runqueue */ #define entity_is_task(se) (!se->my_q) #else #define entity_is_task(se) 1 #endif static inline struct task_struct *task_of(struct sched_entity *se) { return container_of(se, struct task_struct, se); } static inline struct sched_statistics * __schedstats_from_se(struct sched_entity *se) { #ifdef CONFIG_FAIR_GROUP_SCHED if (!entity_is_task(se)) return &container_of(se, struct sched_entity_stats, se)->stats; #endif return &task_of(se)->stats; } #endif static int lve_sched_stat_show(struct seq_file *m, void *v) { #define LVE_CGROUP_CPU_STAT_LEN (255) #define LVE_CPU_STAT_THROTTLE "throttled_time" int rc; struct switch_data *sw_data; u64 total_iowait, throttled_cpu, total_sleep; unsigned long throttled_io = 0UL; /* buf size selected with respect to cpu.stat size */ char buf[LVE_CGROUP_CPU_STAT_LEN + 1]; char *pos; struct file *f; struct light_ve *ve; char tmp[sizeof(LVE_CPU_STAT_THROTTLE)]; struct sched_statistics *stats; if (!is_in_lve(current)) return -EPERM; #ifdef HAVE_TASK_STAT stats = __schedstats_from_se(¤t->se); #else #ifdef HAVE_SCHED_STAT_PTR stats = current->se.statistics; #else stats = ¤t->se.statistics; #endif #endif memset(buf, 0, LVE_CGROUP_CPU_STAT_LEN + 1); sw_data = LVE_TAG_GET(current); if (sw_data == NULL || sw_data->sw_from == NULL) return -EINVAL; ve = sw_data->sw_from; f = lve_private(ve)->filps[PARAM_CPU_THROTTLE]; throttled_io = lve_get_io_throttled_time(ve); rc = cgrp_param_get_string(f, buf, LVE_CGROUP_CPU_STAT_LEN); LVE_TAG_PUT(sw_data); if (rc < 0) return rc; pos = strnstr(buf, LVE_CPU_STAT_THROTTLE, LVE_CGROUP_CPU_STAT_LEN); if (pos == NULL) return -EINVAL; sscanf(pos, "%s%llu\n", tmp, &throttled_cpu); total_iowait = stats->iowait_sum; total_sleep = stats->sum_sleep_runtime; /* Convert to milliseconds */ seq_printf(m, "%u %llu %llu %llu %u\n", jiffies_to_msecs(jiffies), total_sleep / NSEC_PER_MSEC, total_iowait / NSEC_PER_MSEC, throttled_cpu / NSEC_PER_MSEC, jiffies_to_msecs(throttled_io)); return 0; } static int lve_sched_stat_open(struct inode *inode, struct file *file) { return single_open(file, lve_sched_stat_show, NULL); } proc_ops(lve_sched_stat_fops, lve_sched_stat_open, seq_read, NULL, seq_lseek, single_release); /*************** stat end ****************************/ static int lve_dir_stats_show(struct seq_file *m, void *v) { struct light_ve *lve = m->private; lve_stat_hdr_show(m, lve->lve_lvp); lve_stat_show(m, lve); return 0; } static int lve_dir_net_stats_show(struct seq_file *m, void *v) { lve_net_stat_show(m, m->private); return 0; } static int lve_dir_stats_open(struct inode *inode, struct file *file) { light_ve_get(PDE_DATA(inode)); return single_open(file, lve_dir_stats_show, PDE_DATA(inode)); } static int lve_dir_net_stats_open(struct inode *inode, struct file *file) { light_ve_get(PDE_DATA(inode)); return single_open(file, lve_dir_net_stats_show, PDE_DATA(inode)); } proc_ops(lve_dir_stats_fops, lve_dir_stats_open, seq_read, NULL, seq_lseek, single_release); proc_ops(lve_dir_net_stats_fops, lve_dir_net_stats_open, seq_read, NULL, seq_lseek, lve_single_release); int lve_stats_dir_init(struct light_ve *lve) { struct proc_dir_entry *lve_dir; char name[30]; #ifndef LVE_PER_VE if (lve->lve_lvp->lvp_id != ROOT_LVP) return 0; #endif if (lve->lve_id != ROOT_LVE) snprintf(name, sizeof(name)-1, "%u", lve->lve_id); else snprintf(name, sizeof(name)-1, "default"); lve_dir = proc_mkdir(name, lve->lve_lvp->lvp_stats_root); if (lve_dir == NULL) return -EINVAL; light_ve_get(lve); lve->lve_proc_dir = lve_dir; proc_create_data( "stat", S_IRUGO, lve_dir, &lve_dir_stats_fops, lve); proc_create_data("net_stat", S_IRUGO, lve_dir, &lve_dir_net_stats_fops, lve); return 0; } void lve_stats_dir_fini(struct light_ve *lve) { char name[30]; if (lve->lve_proc_dir == NULL) return; if (lve->lve_id != ROOT_LVE) snprintf(name, sizeof(name)-1, "%u", lve->lve_id); else snprintf(name, sizeof(name)-1, "default"); LVE_DBG("remove proc %s\n", name); remove_proc_entry("stat", lve->lve_proc_dir); remove_proc_entry("net_stat", lve->lve_proc_dir); remove_proc_entry(name, lve->lve_lvp->lvp_stats_root); light_ve_put(lve); } /* XXX need refcount protection with replace lvp_sem to lock */ /* reseler defaults limits prints*/ /* OpenVZ print just own user default */ static void * defaults_start(struct seq_file *m, loff_t *pos) { void *ret; if (*pos) return NULL; read_lock(&lvp_lock); m->private = SEQ_START_TOKEN; #ifdef LVE_PER_VE ret = TASK_VE_PRIVATE(current); #else ret = list_first_entry_or_null(&lvp_list, struct lvp_ve_private, lvp_link); lvp_get(ret); #endif read_unlock(&lvp_lock); return ret; } static int defaults_show(struct seq_file *m, void *v) { struct lvp_ve_private *lvp = v; if (m->private == SEQ_START_TOKEN) { seq_printf(m, "1:LVE"); /* */ lve_limits_hdr(m); seq_putc(m,'\n'); m->private = NULL; } seq_printf(m, "%u\t", lvp->lvp_id); lve_limits_print(m, lvp->lvp_def_limits); seq_printf(m, "\t%u\t%u", 0, 0); seq_putc(m,'\n'); return 0; } static void * defaults_next(struct seq_file *m, void *v, loff_t *pos) { #ifdef LVE_PER_VE return NULL; #else struct lvp_ve_private *lvp = v; struct lvp_ve_private *next; read_lock(&lvp_lock); ++*pos; if (lvp && !list_is_last(&lvp->lvp_link, &lvp_list)) { next = list_next_entry(lvp, lvp_link); lvp_get(next); } else { next = NULL; } read_unlock(&lvp_lock); lvp_put(lvp); return next; #endif } static void defaults_stop(struct seq_file *m, void *v) { } static const struct seq_operations lve_defaults_op = { .start = defaults_start, .next = defaults_next, .show = defaults_show, .stop = defaults_stop }; static int lve_defaults_open(struct inode *inode, struct file *file) { int ret; ret = seq_open(file, &lve_defaults_op); if (ret) return ret; return 0; } proc_ops(lve_defaults_fops, lve_defaults_open, seq_read, NULL, seq_lseek, seq_release); /****************************************************/ static int lve_map_open(struct inode *inode, struct file *file) { int ret; ret = seq_open(file, &lve_map_op); if (ret) return ret; return 0; } proc_ops(lve_map_fops, lve_map_open, seq_read, NULL, seq_lseek, seq_release); #if defined(FEAT_DC) static int lve_events_open(struct inode *inode, struct file *file) { int ret; ret = seq_open(file, &lve_events_op); if (ret) return ret; return 0; } static ssize_t lve_events_write(struct file *file, const char __user *data, size_t count, loff_t *off) { char str[50], *ptr; int rc; unsigned long new_value; if (!data || count > (sizeof(str) - 1) || *off) return -EINVAL; rc = copy_from_user(str, data, count); if (rc) return -EFAULT; str[count] = '\0'; new_value = simple_strtoul(str, &ptr, 0); if (ptr == str) return -EINVAL; lve_events_flush(new_value); return count; } proc_ops(lve_events_fops, lve_events_open, seq_read, lve_events_write, seq_lseek, seq_release); #endif /****************************************************/ #define RESELLERS_DIR "resellers" int lvp_proc_init(struct lvp_ve_private *lvp) { struct proc_dir_entry *root, *lve_proc_root; char name[100]; root = lve_procfs_root(lvp); #ifndef LVE_PER_VE /* XXX ugly - just for fast test now */ if (lvp->lvp_id != ROOT_LVP) { snprintf(name, sizeof(name), RESELLERS_DIR"/lvp%d", lvp->lvp_id); root = root_lvp->lvp_proc_root; } else #endif snprintf(name, sizeof(name), "lve"); lve_proc_root = lve_call(proc_mkdir(name, root), LVE_FAIL_INIT_LVP_PROC, NULL); LVE_DBG("root=%px lve_proc_root=%px\n", root, lve_proc_root); if (!lve_proc_root) return -ENOMEM; lvp_get(lvp); lvp->lvp_proc_root = lve_proc_root; proc_create_data("list", S_IRUGO, lve_proc_root, &lve_list_fops, lvp); proc_create_data("usage", S_IRUGO, lve_proc_root, &lve_usage_fops, lvp); proc_create_data("enter", S_IRUGO, lve_proc_root, &lve_enter_fops, lvp); lvp->lvp_stats_root = proc_mkdir("per-lve", lve_proc_root); if (lvp->lvp_id == ROOT_LVP) { proc_create("defaults", S_IRUGO, lve_proc_root, &lve_defaults_fops); #ifndef LVE_PER_VE proc_create("map", S_IRUGO, lve_proc_root, &lve_map_fops); #endif proc_create("debug", S_IRUGO, lve_proc_root, &lve_debug_fops); proc_create("fail", S_IRUGO, lve_proc_root, &lve_fail_fops); #if defined (FEAT_DC) proc_create("events", S_IRUGO, lve_proc_root, &lve_events_fops); #endif proc_create("task_sched_stat", S_IRUGO, lve_proc_root, &lve_sched_stat_fops); proc_mkdir(RESELLERS_DIR, lve_proc_root); } return 0; } int lvp_proc_fini(struct lvp_ve_private *lvp) { struct proc_dir_entry *root; char name[100]; if (!lvp->lvp_proc_root) return 0; remove_proc_entry("enter", lvp->lvp_proc_root); remove_proc_entry("usage", lvp->lvp_proc_root); remove_proc_entry("list", lvp->lvp_proc_root); /* */ remove_proc_entry("per-lve", lvp->lvp_proc_root); if (lvp->lvp_id == ROOT_LVP) { remove_proc_entry("defaults", lvp->lvp_proc_root); #ifndef LVE_PER_VE remove_proc_entry("map", lvp->lvp_proc_root); #endif remove_proc_entry("fail", lvp->lvp_proc_root); remove_proc_entry("debug", lvp->lvp_proc_root); #ifdef FEAT_DC remove_proc_entry("events", lvp->lvp_proc_root); #endif remove_proc_entry("task_sched_stat", lvp->lvp_proc_root); remove_proc_entry(RESELLERS_DIR, lvp->lvp_proc_root); } /* */ root = lve_procfs_root(lvp); #ifndef LVE_PER_VE /* XXX ugly - just for fast test now */ if (lvp->lvp_id != ROOT_LVP) { snprintf(name, sizeof(name), RESELLERS_DIR"/lvp%d", lvp->lvp_id); root = root_lvp->lvp_proc_root; } else #endif snprintf(name, sizeof(name), "lve"); remove_proc_entry(name, root); lvp_put(lvp); return 0; }