summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzy <[email protected]>2023-11-09 05:20:54 -0500
committerzy <[email protected]>2023-11-09 05:20:54 -0500
commitacf7a2f402312dc30bba199c24e40fde390ffd42 (patch)
tree3187aa3d2f590fafc63a991094f93b8cee69a437
parentb5e1952f29fcb8bd7f3f58701bd95832c912b4ed (diff)
watch mult var
-rw-r--r--helloworld.c3
-rw-r--r--watch.c2
-rw-r--r--watch.h6
-rw-r--r--watch_module.c34
-rw-r--r--watch_module.h68
-rw-r--r--watch_module_lib.c182
6 files changed, 236 insertions, 59 deletions
diff --git a/helloworld.c b/helloworld.c
index aef2ac4..3996a0f 100644
--- a/helloworld.c
+++ b/helloworld.c
@@ -11,6 +11,7 @@ int main()
watch_arg watch_arg = {
.task_id = getpid(),
.ptr = &temp,
+ .name = "temp",
.length_byte = sizeof(int),
.threshold = 105,
.unsigned_flag = 1,
@@ -26,6 +27,6 @@ int main()
sleep(1);
}
- cancel_watch();
+ cancel_all_watch();
return 0;
} \ No newline at end of file
diff --git a/watch.c b/watch.c
index 0d384c6..dceb15f 100644
--- a/watch.c
+++ b/watch.c
@@ -30,7 +30,7 @@ int start_watch(watch_arg w_arg)
/// @brief cancel watch
/// @return 0 means success, other means fail
-int cancel_watch()
+int cancel_all_watch()
{
if (file_desc < 0)
{
diff --git a/watch.h b/watch.h
index 4a0d032..24a0574 100644
--- a/watch.h
+++ b/watch.h
@@ -1,9 +1,11 @@
// watch.h
#include <sys/types.h>
+#define MAX_NAME_LEN (15) // max name length
typedef struct
{
pid_t task_id; // current process id
+ char name[MAX_NAME_LEN + 1]; // name
void *ptr; // virtual address
int length_byte; // byte
long long threshold; // threshold value
@@ -15,5 +17,5 @@ typedef struct
// start watch
int start_watch(watch_arg w_arg);
-// cancel watch
-int cancel_watch(); \ No newline at end of file
+// cancel all watch
+int cancel_all_watch(); \ No newline at end of file
diff --git a/watch_module.c b/watch_module.c
index 04aff1d..a6b900e 100644
--- a/watch_module.c
+++ b/watch_module.c
@@ -23,12 +23,9 @@ static int device_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "%s\n", __FUNCTION__);
// unmap and release the page
- if (kaddr)
- kunmap(kaddr);
- if (page)
- put_page(page);
+ free_page_list();
// cancel timer
- cancel_hrTimer();
+ cancel_all_hrTimer();
return 0;
}
@@ -36,17 +33,18 @@ static long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned lon
{
watch_arg warg;
void *ptr;
+ kernel_watch_timer *timer = NULL;
+ kernel_watch_arg k_watch_arg;
// copy watch_arg
if (copy_from_user(&warg, (watch_arg *)ioctl_param, sizeof(warg)))
{
return -EACCES;
}
- printk(KERN_INFO "Received: task_id=%d, ptr=%p, length_byte=%d, time_ns=%ld, threshold=%lld\n", warg.task_id, warg.ptr,
- warg.length_byte, warg.time_ns, warg.threshold);
+ printk(KERN_INFO "Received: task_id=%d, name=%s, ptr=%p, length_byte=%d, time_ns=%ld, threshold=%lld\n",
+ warg.task_id, warg.name, warg.ptr, warg.length_byte, warg.time_ns, warg.threshold);
// user space address to kernel space address
ptr = access_user_space_ptr(warg.task_id, (unsigned long)warg.ptr);
-
if (ptr == NULL)
{
printk(KERN_ERR "Cannot access user space\n");
@@ -58,17 +56,19 @@ static long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned lon
printk(KERN_ERR "Invalid length %d\n", warg.length_byte);
return -EINVAL;
}
-
// k_watch_arg init
- k_watch_arg.kptr = ptr;
- k_watch_arg.length_byte = warg.length_byte;
- k_watch_arg.threshold = warg.threshold;
- k_watch_arg.unsigned_flag = warg.unsigned_flag;
- k_watch_arg.greater_flag = warg.greater_flag;
- // start timer
- start_hrTimer(warg.time_ns);
- printk(KERN_INFO "Start watching\n");
+ w_arg2k_w_arg(ptr, warg, &k_watch_arg);
+ timer = get_timer(warg.time_ns); // get a valuable timer
+ printk(KERN_INFO "timer: %p\n", timer);
+ printk(KERN_INFO "timer->sentinel: %d, timer->time_ns: %lld\n", timer->sentinel, timer->time_ns);
+ printk(KERN_INFO "timer->hr_timer: %p\n", &timer->hr_timer);
+
+ TIMER_CANCEL(timer); // just in case
+ timer_add_watch(timer, k_watch_arg);
+ TIMER_START(timer);
+
+ printk(KERN_INFO "Start watching\n");
return 0;
}
diff --git a/watch_module.h b/watch_module.h
index d4f48c5..41a49ff 100644
--- a/watch_module.h
+++ b/watch_module.h
@@ -1,6 +1,9 @@
#include <linux/hrtimer.h>
#include <linux/kprobes.h>
#include <linux/ktime.h>
+#include <linux/list.h>
+#include <linux/slab.h> /* for kmalloc */
+#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
@@ -11,44 +14,85 @@
#include <linux/sched/signal.h>
#include <linux/stacktrace.h> /* for stack_trace_print */
+#define MAX_TIMER_NUM (2048) // max timer number
+#define TIMER_MAX_WATCH_NUM (32) // A timer max watch number at once time
+#define MAX_NAME_LEN (15) // max name length
typedef struct
{
pid_t task_id; // current process id
+ char name[MAX_NAME_LEN + 1]; // name
void *ptr; // virtual address
- int length_byte; // byte
+ int length_byte; // byte
long long threshold; // threshold value
unsigned char unsigned_flag; // unsigned flag (true: unsigned, false: signed)
unsigned char greater_flag; // reverse flag (true: >, false: <)
- unsigned long time_ns; // timer interval (ns)
+ unsigned long time_ns; // timer interval (ns)
} watch_arg;
typedef struct
{
+ char name[MAX_NAME_LEN + 2]; // name, last char automatically add '\0'
void *kptr; // kernel address + offset
- int length_byte; // byte
+ int length_byte; // byte
long long threshold; // threshold value
unsigned char unsigned_flag; // unsigned flag (true: unsigned, false: signed)
unsigned char greater_flag; // reverse flag (true: >, false: <)
} kernel_watch_arg;
-kernel_watch_arg k_watch_arg;
-EXPORT_SYMBOL(k_watch_arg); // export k_watch_arg
+typedef struct
+{
+ unsigned long long time_ns; // hrTimer time interval (ns)
+ struct hrtimer hr_timer; // hrTimer
+ ktime_t kt; // hrTimer time
+ unsigned sentinel; // sentinel
+ kernel_watch_arg k_watch_args[TIMER_MAX_WATCH_NUM]; // all watched kernel_watch_arg
+} kernel_watch_timer;
+
+#define TIMER_FILLED(timer) ((timer)->sentinel >= TIMER_MAX_WATCH_NUM)
+#define TIMER_EMPTY(timer) (!((timer)->time_ns | (timer)->sentinel))
+
+#define TIMER_START(timer) (hrtimer_start(&timer->hr_timer, timer->kt, HRTIMER_MODE_REL))
+#define TIMER_CANCEL(timer) (hrtimer_cancel(&timer->hr_timer))
+
+kernel_watch_timer kernel_wtimer_list[MAX_TIMER_NUM] = {0}; // all kernel_watch_timer
+int kernel_wtimer_num = 0; // current kernel_watch_timer number
+
+EXPORT_SYMBOL(kernel_wtimer_list); // export kernel_watch_timer_list
+EXPORT_SYMBOL(kernel_wtimer_num); // export kernel_watch_timer_num
+
+// Helper function
+unsigned char w_arg2k_w_arg(void *ptr, watch_arg warg, kernel_watch_arg *k_watch_arg);
+
+// for timer
+kernel_watch_timer *get_timer(unsigned long long time_ns);
+unsigned char timer_add_watch(kernel_watch_timer *timer, kernel_watch_arg k_watch_arg);
// for memory access
-static struct page *page = NULL;
-static void *kaddr = NULL;
+typedef struct
+{
+ struct page *page;
+ void *kaddr;
+ struct list_head entry;
+} watch_local_memory;
+
+static LIST_HEAD(watch_local_memory_list);
+
+void free_page_list(void);
+
+// static struct page *page = NULL;
+// static void *kaddr = NULL;
void *access_user_space_ptr(pid_t pid, unsigned long kaddr);
// for timer
#define US2NS (1000) // Interval in microseconds
-static struct hrtimer hr_timer;
-static ktime_t kt;
+// static struct hrtimer hr_timer;
+// static ktime_t kt;
// hrTimer
enum hrtimer_restart hrtimer_hander(struct hrtimer *timer);
-int start_hrTimer(unsigned long timeout);
-void cancel_hrTimer(void);
+// int start_hrTimer(unsigned long timeout);
+void cancel_all_hrTimer(void);
unsigned char read_and_compare(kernel_watch_arg *k_arg);
@@ -95,8 +139,6 @@ static void print_all_task_stack(void)
unsigned long backtrace[BACKTRACE_DEPTH]; // save stack
unsigned int nr_bt; // stack depth
unsigned long long current_time; // last time
- printk("-------------------------------------\n");
- printk("-------------watch monitor-----------\n");
current_time = ktime_get_real();
printk("Timestamp (ns): %lld\n", current_time);
printk("Recent Load: %lu.%02lu, %lu.%02lu, %lu.%02lu\n", // recent load
diff --git a/watch_module_lib.c b/watch_module_lib.c
index 28bd3a0..43eb08b 100644
--- a/watch_module_lib.c
+++ b/watch_module_lib.c
@@ -1,5 +1,80 @@
#include "watch_module.h"
+unsigned char w_arg2k_w_arg(void *ptr, watch_arg warg, kernel_watch_arg *k_watch_arg)
+{
+ // k_watch_arg init
+ strncpy(k_watch_arg->name, warg.name, MAX_NAME_LEN + 1); // name
+ k_watch_arg->name[MAX_NAME_LEN + 1] = '\0'; // just in case
+ k_watch_arg->kptr = ptr;
+ k_watch_arg->length_byte = warg.length_byte;
+ k_watch_arg->threshold = warg.threshold;
+ k_watch_arg->unsigned_flag = warg.unsigned_flag;
+ k_watch_arg->greater_flag = warg.greater_flag;
+ return 0;
+}
+
+/// @brief get a valuable timer
+/// @param time_ns
+/// @return kernel_watch_timer *, NULL means fail
+kernel_watch_timer *get_timer(unsigned long long time_ns)
+{
+ int i = 0;
+ kernel_watch_timer *timer = NULL;
+ // chose a timer
+ for (i = 0; i < kernel_wtimer_num; i++)
+ {
+ timer = &kernel_wtimer_list[i];
+
+ if (TIMER_EMPTY(timer)){
+ break;
+ }
+ if ((timer->time_ns == time_ns) && (!TIMER_FILLED(timer)))
+ {
+ break;
+ }
+ }
+ // if all timer is full
+ if (i >= MAX_TIMER_NUM)
+ {
+ printk(KERN_ERR "No timer available\n");
+ return NULL;
+ }
+ // if a new timer, init it
+ if (i > kernel_wtimer_num - 1)
+ {
+ printk(KERN_INFO "New timer\n");
+
+ kernel_wtimer_list[i].time_ns = time_ns;
+ kernel_wtimer_list[i].sentinel = 0;
+
+ kernel_wtimer_list[i].kt = ktime_set(0, (unsigned long)time_ns); // ns
+ // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time
+ hrtimer_init(&(kernel_wtimer_list[i].hr_timer), CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ kernel_wtimer_list[i].hr_timer.function = hrtimer_hander; // callback function
+
+ kernel_wtimer_num = i + 1;
+ }
+
+ return &kernel_wtimer_list[i];
+}
+
+/// @brief hrTimer add watch
+/// @param timer
+/// @param k_watch_arg
+/// @return 0 is success
+unsigned char timer_add_watch(kernel_watch_timer *timer, kernel_watch_arg k_watch_arg)
+{
+ if (TIMER_FILLED(timer))
+ {
+ printk(KERN_ERR "Timer is full\n");
+ return -1;
+ }
+ memcpy(&timer->k_watch_args[timer->sentinel], &k_watch_arg, sizeof(k_watch_arg));
+ // timer->k_watch_args[timer->sentinel] = k_watch_arg;
+ timer->sentinel++;
+ return 0;
+}
+
/// @brief transfer user space address to kernel space address
/// change static global "kaddr" and "page" value
/// @param pid: process id
@@ -11,12 +86,25 @@ void *access_user_space_ptr(pid_t pid, unsigned long addr)
struct mm_struct *mm;
int ret;
+ // unsigned long aligned_addr = 0;
+ // unsigned long offset = 0;
+
+ watch_local_memory *node;
+
+ // if (addr < TASK_SIZE || addr > -PAGE_SIZE)
+ // {
+ // printk(KERN_ERR "Invalid address\n");
+ // return NULL;
+ // }
+
// for get_user_pages_remote
unsigned long aligned_addr = addr & PAGE_MASK;
unsigned long offset = addr & ~PAGE_MASK;
printk(KERN_INFO "%s\n", __FUNCTION__);
+ node = kmalloc(sizeof(watch_local_memory), GFP_KERNEL);
+
// Find the task with pid
rcu_read_lock();
task = pid_task(find_vpid(pid), PIDTYPE_PID);
@@ -25,73 +113,117 @@ void *access_user_space_ptr(pid_t pid, unsigned long addr)
if (!task)
{
printk(KERN_ERR "Cannot find task for PID %d\n", pid);
+ kfree(node); // careful there is kfree
return NULL;
}
-
// Get memory descriptor
mm = get_task_mm(task);
if (!mm)
{
printk(KERN_ERR "Cannot get memory descriptor\n");
+ kfree(node); // careful there is kfree
return NULL;
}
-
down_read(&task->mm->mmap_lock);
- ret = get_user_pages_remote(task->mm, aligned_addr, 1, FOLL_FORCE, &page, NULL, NULL);
+ ret = get_user_pages_remote(task->mm, aligned_addr, 1, FOLL_FORCE, &(node->page), NULL, NULL);
up_read(&task->mm->mmap_lock);
if (ret != 1)
{
printk(KERN_ERR "Cannot get user page\n");
+ kfree(node); // careful there is kfree
return NULL;
}
-
// Map the page to kernel space
- kaddr = kmap(page);
- return kaddr + offset;
+ node->kaddr = kmap(node->page);
+ list_add_tail(&node->entry, &watch_local_memory_list); // add to list
+ printk(KERN_INFO "node->kaddr: %p, aligned_addr: %ld, offset: %ld\n", node->kaddr, aligned_addr, offset);
+ return (node->kaddr) + offset;
}
+/// @brief free all page in watch_local_memory_list
+/// @param
+void free_page_list(void)
+{
+ watch_local_memory *node, *next;
+ list_for_each_entry_safe(node, next, &watch_local_memory_list, entry)
+ {
+ if (node == NULL)
+ break;
+ // unmap and release the page
+ if (node->kaddr)
+ kunmap(node->kaddr);
+ if (node->page)
+ put_page(node->page);
+ list_del(&node->entry);
+ kfree(node); // careful there is kfree
+ }
+}
/// @brief hrTimer handler
enum hrtimer_restart hrtimer_hander(struct hrtimer *timer)
{
- if (read_and_compare(&k_watch_arg))
+ kernel_watch_timer *k_watch_timer = container_of(timer, kernel_watch_timer, hr_timer);
+ int i = 0, j = 0;
+ char buffer[1024] = {0}; // Buffer to store the messages
+
+ // check all watched kernel_watch_arg
+ for (i = 0; i < k_watch_timer->sentinel; i++)
{
- // printk(KERN_INFO "Threshold reached\n");
+ if (read_and_compare(&k_watch_timer->k_watch_args[i]))
+ {
+ snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "%s ,",
+ k_watch_timer->k_watch_args[i].name);
+ j++;
+ }
+ }
+ if (j > 0) // if any threshold reached
+ {
+ printk("-------------------------------------\n");
+ printk("-------------watch monitor-----------\n");
+ printk("Threshold reached var name: %s\n", buffer);
print_all_task_stack();
- // after 1s restart timer
+ // restart timer after 1s
hrtimer_forward(timer, timer->base->get_time(), ktime_set(1, 0));
+ printk("-------------------------------------\n");
}
else
{
// keep frequency
- hrtimer_forward(timer, timer->base->get_time(), kt);
+ hrtimer_forward(timer, timer->base->get_time(), k_watch_timer->kt);
}
- // restart timer
- return HRTIMER_RESTART;
+ return HRTIMER_RESTART; // restart timer
}
/// @brief start hrTimer
/// @param timeout: timeout in us
/// @return 0 is success
-int start_hrTimer(unsigned long timeout)
-{
- printk("HrTimer Start\n");
+// int start_hrTimer(unsigned long timeout)
+// {
+// printk("HrTimer Start\n");
- kt = ktime_set(0, (unsigned long)timeout); // us -> ns
- // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time
- hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hr_timer.function = hrtimer_hander;
- // mode the same as hrtimer_init
- hrtimer_start(&hr_timer, kt, HRTIMER_MODE_REL);
- return 0;
-}
+// kt = ktime_set(0, (unsigned long)timeout); // us -> ns
+// // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time
+// hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+// hr_timer.function = hrtimer_hander;
+// // mode the same as hrtimer_init
+// hrtimer_start(&hr_timer, kt, HRTIMER_MODE_REL);
+// return 0;
+// }
/// @brief cancel hrTimer
/// @param
-void cancel_hrTimer(void)
+void cancel_all_hrTimer(void)
{
- hrtimer_cancel(&hr_timer);
+ int i = 0;
+ kernel_watch_timer *timer = NULL;
+ for (i = 0; i < kernel_wtimer_num; i++)
+ {
+ timer = &(kernel_wtimer_list[i]);
+ TIMER_CANCEL(timer);
+ }
+
+ // hrtimer_cancel(&hr_timer);
printk("HrTimer End\n");
}