X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fvserver%2Fhistory.c;h=7a7bf1fcf00ec6b06ea1bbb0e380fc28ef238bcf;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=f1e3e6cf4fa64e645619ced7a5eceaa078ab7659;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/kernel/vserver/history.c b/kernel/vserver/history.c index f1e3e6cf4..7a7bf1fcf 100644 --- a/kernel/vserver/history.c +++ b/kernel/vserver/history.c @@ -3,7 +3,7 @@ * * Virtual Context History Backtrace * - * Copyright (C) 2004-2005 Herbert Pötzl + * Copyright (C) 2004-2007 Herbert Pötzl * * V0.01 basic structure * V0.02 hash/unhash and trace @@ -20,7 +20,10 @@ #include #include +#include #include +#include +#include #ifdef CONFIG_VSERVER_HISTORY @@ -62,6 +65,8 @@ struct _vx_hist_entry *vxh_advance(void *loc) return entry; } +EXPORT_SYMBOL_GPL(vxh_advance); + #define VXH_LOC_FMTS "(#%04x,*%d):%p" @@ -170,7 +175,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(); @@ -179,5 +184,81 @@ int vc_dump_history(uint32_t id) return 0; } -EXPORT_SYMBOL_GPL(vxh_advance); + +int do_read_history(struct __user _vx_hist_entry *data, + int cpu, uint32_t *index, uint32_t *count) +{ + int pos, ret = 0; + struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu); + int end = hist->counter; + int start = end - VXH_SIZE + 2; + int idx = *index; + + /* special case: get current pos */ + if (!*count) { + *index = end; + return 0; + } + + /* have we lost some data? */ + if (idx < start) + idx = start; + + for (pos = 0; (pos < *count) && (idx < end); pos++, idx++) { + struct _vx_hist_entry *entry = + &hist->entry[idx % VXH_SIZE]; + + /* send entry to userspace */ + ret = copy_to_user (&data[pos], entry, sizeof(*entry)); + if (ret) + break; + } + /* save new index and count */ + *index = idx; + *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 (id >= NR_CPUS) + return -EINVAL; + + 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 (id >= NR_CPUS) + return -EINVAL; + + 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 */