fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / kernel / vserver / history.c
index f1e3e6c..7a7bf1f 100644 (file)
@@ -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
 #include <asm/atomic.h>
 #include <asm/unistd.h>
 
+#include <linux/vserver/context.h>
 #include <linux/vserver/debug.h>
+#include <linux/vserver/debug_cmd.h>
+#include <linux/vserver/history.h>
 
 
 #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 */