Я резервирую буфер (максималь*но 200мб) для худшего случая ...
Но предпочтит*ельнее создать список из буферов (например по 1 мб). Помогите! Не получается.
Модуль:
Код:
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kallsyms.h>
#include <linux/kprobes.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/time.h>
static struct jprobe jp;
#define PROC_FILE "switches"
struct proc_dir_entry * proc_file;
// Module parameters
// Pidы, за которыми будем следить
#define MAX_PIDS_NUMBER 1024
static int pids[MAX_PIDS_NUMBER];
static int pids_number = 0;
module_param_array(pids, int, &pids_number, S_IRUGO | S_IWUSR);
// Будем следить за всеми pidами
static bool all = false;
module_param(all, bool, S_IRUGO | S_IWUSR);
// Время, после которого стирается информация о переключении
static int buffer_time = 10;
module_param(buffer_time, int, S_IRUGO | S_IWUSR);
// Максимально возможное количество запомненных переключений
static int MAX_LIST = 100000;
module_param(MAX_LIST, int, S_IRUGO);
// Список процессоров, за которыми мы следим
#define MAX_CPUS 128
static int cpus[MAX_CPUS];
static int cpus_number = 0;
module_param_array(cpus, int, &cpus_number, S_IRUGO | S_IWUSR);
// Удалять ли запись после чтения
static bool clear_on_read = true;
module_param(clear_on_read, bool, S_IRUGO | S_IWUSR);
// Реализация списка на базе массива
struct list_entry {
int pid;
int next, prev;
int timestamp;
int cpu;
bool already_read;
};
static int list_size = 0;
static int list_head = 0;
static struct list_entry *list;
static inline int round_by_size (int pos) {
if (pos >= MAX_LIST) {
pos -= MAX_LIST;
}
return pos;
}
static bool overflow = false;
// Функция для добавления записи о переключении контектса в список
// и, если это потребуется, частичной очистки списка по времени
static int add_list_entry(int pid, int prev, int next, int cpu) {
struct list_entry entry;
struct timeval t;
int i;
int pos;
do_gettimeofday(&t);
for (i = 0; i < list_size; i++) {
pos = round_by_size(i + list_head);
if ( ( t.tv_sec - list[ pos ].timestamp > buffer_time )
|| ( clear_on_read && list[pos].already_read ) ) {
list_head = round_by_size(list_head + 1);
list_size--;
} else {
break;
}
}
// Добавляем новый элемент списка запомненных переключений
entry.pid = pid;
entry.prev = prev;
entry.next = next;
entry.cpu = cpu;
entry.timestamp = t.tv_sec;
list_size++;
pos = round_by_size(list_size + list_head);
list[ pos ] = entry;
if (list_size >= MAX_LIST) {
if (overflow == false) {
printk(KERN_WARNING "Buffer overflow! Please, stop the module and resize buffer.\n");
overflow = true;
}
list_head = round_by_size(list_head+1);
list_size--;
}
return 0;
}
// Функция, которая подменяет собой вызов __switch_to
// и, отработав, вызывает ее
struct task_struct *switch_handler(
struct task_struct *prev,
struct task_struct *next
) {
int i;
pid_t pid_prev = prev->pid;
pid_t pid_next = next->pid;
int cpu = task_cpu(next);
if (cpus_number > 0) {
for (i = 0; i < cpus_number; i++) {
if (cpus[i] == cpu) {
break;
}
}
if (cpus[i] != cpu) {
jprobe_return();
}
}
if (true == all) {
add_list_entry(pid_prev, pid_prev, pid_next, cpu);
add_list_entry(pid_next, pid_prev, pid_next, cpu);
} else {
for (i = 0; i < pids_number; i++) {
if (pids[i] == pid_prev) {
add_list_entry(pid_prev, pid_prev, pid_next, cpu);
} else if (pids[i] == pid_next) {
add_list_entry(pid_next, pid_prev, pid_next, cpu);
}
}
}
jprobe_return();
return 0;
}
// Печать списка в proc файл
static void *switches_seq_start (struct seq_file *s, loff_t *pos) {
int i;
if (*pos >= list_size) {
return NULL;
}
i = round_by_size(list_head + *pos);
return &list[ i ];
}
static void *switches_seq_next(struct seq_file *s, void *v, loff_t *pos) {
int i;
(*pos)++;
if (*pos >- list_size) {
return NULL;
}
i = round_by_size(list_head + *pos);
return &list[ i];
}