diff -NurpP --minimal linux-2.6.18-vs2.1.1-rc36/include/linux/vserver/debug_cmd.h linux-2.6.18-vs2.1.1-rc36.1/include/linux/vserver/debug_cmd.h --- linux-2.6.18-vs2.1.1-rc36/include/linux/vserver/debug_cmd.h 2006-09-20 17:01:45 +0200 +++ linux-2.6.18-vs2.1.1-rc36.1/include/linux/vserver/debug_cmd.h 2006-10-07 02:20:08 +0200 @@ -6,9 +6,51 @@ #define VCMD_dump_history VC_CMD(DEBUG, 1, 0) +#define VCMD_read_history VC_CMD(DEBUG, 5, 0) +#define VCMD_read_monitor VC_CMD(DEBUG, 6, 0) + +struct vcmd_read_history_v0 { + int32_t index; + int32_t count; + char __user *data; +}; + +struct vcmd_read_monitor_v0 { + int32_t index; + int32_t count; + char __user *data; +}; + + #ifdef __KERNEL__ +#ifdef CONFIG_COMPAT + +struct vcmd_read_history_v0_x32 { + int32_t index; + int32_t count; + compat_uptr_t data_ptr; +} + +struct vcmd_read_monitor_v0_x32 { + int32_t index; + int32_t count; + compat_uptr_t data_ptr; +} + +#endif /* CONFIG_COMPAT */ + extern int vc_dump_history(uint32_t); +extern int vc_read_history(uint32_t, void __user *); +extern int vc_read_monitor(uint32_t, void __user *); + +#ifdef CONFIG_COMPAT + +extern int vc_read_history_x32(uint32_t, void __user *); +extern int vc_read_monitor_x32(uint32_t, void __user *); + +#endif /* CONFIG_COMPAT */ + #endif /* __KERNEL__ */ #endif /* _VX_DEBUG_CMD_H */ diff -NurpP --minimal linux-2.6.18-vs2.1.1-rc36/kernel/vserver/history.c linux-2.6.18-vs2.1.1-rc36.1/kernel/vserver/history.c --- linux-2.6.18-vs2.1.1-rc36/kernel/vserver/history.c 2006-09-25 15:40:02 +0200 +++ linux-2.6.18-vs2.1.1-rc36.1/kernel/vserver/history.c 2006-10-07 04:21:29 +0200 @@ -21,6 +21,7 @@ #include #include +#include #include @@ -63,6 +64,8 @@ struct _vx_hist_entry *vxh_advance(void return entry; } +EXPORT_SYMBOL_GPL(vxh_advance); + #define VXH_LOC_FMTS "(#%04x,*%d):%p" @@ -171,7 +174,7 @@ void vxh_dump_history(void) /* vserver syscall commands below here */ -int vc_dump_history(uint32_t id) +int vc_dump_history(uint32_t id) { vxh_active = 0; __vxh_dump_history(); @@ -180,5 +183,75 @@ int vc_dump_history(uint32_t id) return 0; } -EXPORT_SYMBOL_GPL(vxh_advance); + +int do_read_history(struct __user _vx_hist_entry *data, + uint32_t id, uint32_t *index, uint32_t *count) +{ + int pos, ret = 0, cpu = id % NR_CPUS; + struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu); + int end = hist->counter; + int start = end - VXH_SIZE + 2; + int delta = *index; + + /* special case: get current pos */ + if (!*count) { + *index = end; + return 0; + } + + /* have we lost some data? */ + if (delta < start) + delta = start; + + for (pos = 0; (pos < *count) && (delta <= end); pos++) { + struct _vx_hist_entry *entry = + &hist->entry[(delta + pos) & VXH_SIZE]; + + /* send entry to userspace */ + ret = copy_to_user (&data[pos], entry, sizeof(*entry)); + if (ret) + break; + } + /* save new index and count */ + *index = delta + pos; + *count = pos; + return ret ? ret : (*index < end); +} + +int vc_read_history(uint32_t id, void __user *data) +{ + struct vcmd_read_history_v0 vc_data; + int ret; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_read_history((struct __user _vx_hist_entry *)vc_data.data, + id, &vc_data.index, &vc_data.count); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return ret; +} + +#ifdef CONFIG_COMPAT + +int vc_read_history_x32(uint32_t id, void __user *data) +{ + struct vcmd_read_history_v0_x32 vc_data; + int ret; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_read_history((struct __user _vx_hist_entry *) + compat_ptr(vc_data.data_ptr), + id, &vc_data.index, &vc_data.count); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return ret; +} + +#endif /* CONFIG_COMPAT */ diff -NurpP --minimal linux-2.6.18-vs2.1.1-rc36/kernel/vserver/monitor.c linux-2.6.18-vs2.1.1-rc36.1/kernel/vserver/monitor.c --- linux-2.6.18-vs2.1.1-rc36/kernel/vserver/monitor.c 2006-09-25 15:40:02 +0200 +++ linux-2.6.18-vs2.1.1-rc36.1/kernel/vserver/monitor.c 2006-10-07 04:22:18 +0200 @@ -20,6 +20,7 @@ #include #include +#include #ifdef CONFIG_VSERVER_MONITOR @@ -62,3 +63,75 @@ struct _vx_mon_entry *vxm_advance(int cp EXPORT_SYMBOL_GPL(vxm_advance); + +int do_read_monitor(struct __user _vx_mon_entry *data, + uint32_t id, uint32_t *index, uint32_t *count) +{ + int pos, ret = 0, cpu = id % NR_CPUS; + struct _vx_monitor *mon = &per_cpu(vx_monitor_buffer, cpu); + int end = mon->counter; + int start = end - VXM_SIZE + 2; + int delta = *index; + + /* special case: get current pos */ + if (!*count) { + *index = end; + return 0; + } + + /* have we lost some data? */ + if (delta < start) + delta = start; + + for (pos = 0; (pos < *count) && (delta <= end); pos++) { + struct _vx_mon_entry *entry = + &mon->entry[(delta + pos) & VXM_SIZE]; + + /* send entry to userspace */ + ret = copy_to_user (&data[pos], entry, sizeof(*entry)); + if (ret) + break; + } + /* save new index and count */ + *index = delta + pos; + *count = pos; + return ret ? ret : (*index < end); +} + +int vc_read_monitor(uint32_t id, void __user *data) +{ + struct vcmd_read_monitor_v0 vc_data; + int ret; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_read_monitor((struct __user _vx_mon_entry *)vc_data.data, + id, &vc_data.index, &vc_data.count); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return ret; +} + +#ifdef CONFIG_COMPAT + +int vc_read_monitor_x32(uint32_t id, void __user *data) +{ + struct vcmd_read_monitor_v0_x32 vc_data; + int ret; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_read_monitor((struct __user _vx_mon_entry *) + compat_ptr(vc_data.data_ptr), + id, &vc_data.index, &vc_data.count); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return ret; +} + +#endif /* CONFIG_COMPAT */ + diff -NurpP --minimal linux-2.6.18-vs2.1.1-rc36/kernel/vserver/switch.c linux-2.6.18-vs2.1.1-rc36.1/kernel/vserver/switch.c --- linux-2.6.18-vs2.1.1-rc36/kernel/vserver/switch.c 2006-09-29 17:52:30 +0200 +++ linux-2.6.18-vs2.1.1-rc36.1/kernel/vserver/switch.c 2006-10-07 03:13:08 +0200 @@ -218,6 +218,12 @@ long do_vcmd(uint32_t cmd, uint32_t id, #ifdef CONFIG_VSERVER_HISTORY case VCMD_dump_history: return vc_dump_history(id); + case VCMD_read_history: + return __COMPAT(vc_read_history, id, data, compat); +#endif +#ifdef CONFIG_VSERVER_MONITOR + case VCMD_read_monitor: + return __COMPAT(vc_read_monitor, id, data, compat); #endif #ifdef CONFIG_VSERVER_LEGACY case VCMD_new_s_context: @@ -331,6 +337,10 @@ long do_vserver(uint32_t cmd, uint32_t i /* debug level admin commands */ #ifdef CONFIG_VSERVER_HISTORY __VCMD(dump_history, 9, VCA_NONE, 0); + __VCMD(read_history, 9, VCA_NONE, 0); +#endif +#ifdef CONFIG_VSERVER_MONITOR + __VCMD(read_monitor, 9, VCA_NONE, 0); #endif /* legacy commands */