#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <linux/seq_file.h>
//extern uint64_t interrupt_time;
static struct proc_dir_entry *test_dir;
static int my_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%lu\n", jiffies);
//seq_printf(m, "%lu", interrupt_time);
return 0;
}
static int my_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, my_proc_show, NULL);
}
static const struct file_operations tst_fops = {
.open = my_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init test_init(void)
{
test_dir = proc_mkdir("myproc", NULL);
if (test_dir)
proc_create("jiffies", 0, test_dir, &tst_fops);
return 0;
}
static void __exit test_exit(void)
{
remove_proc_entry ("jiffies", test_dir);
proc_remove (test_dir);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Test");
The above code is for procfs driver in which the above code contains the init function, exit function, file operation function but how to create a seq_read() function from kernel to user. What is the API for that?
This is the code I modified in /linuxversion/net/core/dev.c
int netif_rx(struct sk_buff *skb)
{
skb->tstamp = ktime_get_real(); //this will give a timestamp and it will be stored in //skb buffer
//I am calculating a timestamp here. because whenever kernel receive the data then the kernel is
//interrupted and start executing the newly arrived task but I have to read the time when the
//interrupt occurs and get the value of it.
}
My question is: How to copy this time-stamp to procfs?
I'm not sure if your issue is how to create and populate entries in /proc or how to read from an existing one. Regarding the latter:
how to read it to the user application
From the user program open /proc/foo/bar and read from it, as from any other file.
Related
I am trying to get a list of all PIDs in a kernel module without useful APIs for some reason.
The code is here. I tried to scan all existing task_struct objects connected with sibling/children member in struct task_struct.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/init_task.h>
MODULE_LICENSE("Dual BSD/GPL");
#define MODNAME "list_pid"
#define MINOR_COUNT 1
static void printk_pid_children(struct task_struct *parent_ts){
struct task_struct *fst = container_of(parent_ts->children.next, struct task_struct, sibling);
struct task_struct *t = fst;
if(fst != parent_ts){
do {
printk("%d,", t->tgid);
printk_pid_children(t);
t = list_next_entry(t, sibling);
} while(t != fst);
}
}
static int __init list_pid_init(void){
printk("%s\n",__func__);
printk("%d,", init_task.pid);
printk_pid_children(&init_task);
printk("\n");
return 0;
}
module_init(list_pid_init);
static void __exit list_pid_exit(void){
}
module_exit(list_pid_exit);
However, after sudo insmod list_pid.ko, the system hangs up.
What is wrong in the above code?
Thank you.
I wrote this linux char driver just to control open call,
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/semaphore.h>
#include <linux/device.h>
#include <linux/cdev.h>
MODULE_LICENSE("GPL");
#define CLASS_NAME "myclass"
#define MINOR_NUM 0
#define MINOR_CNT 1
static struct class *myclass=NULL;
static struct device *mydevice=NULL;
static dev_t mycdevt;
static struct cdev *mycdev;
static struct semaphore *sem;
static int myopen(struct inode *inod, struct file *fp)
{
down(sem);
printk(KERN_INFO "critical section\n");
return 0;
}
static int myclose(struct inode *inod, struct file *fp )
{
up(sem);
printk(KERN_INFO "critical section freed\n");
return 0;
}
static ssize_t myread(struct file *fp, char *buf, size_t len, loff_t *off)
{
return 0;
}
static ssize_t mywrite(struct file *fp, char *buf, size_t len, loff_t *off)
{
return 0;
}
static struct file_operations fops =
{
.open = myopen,
.release = myclose,
.read = myread,
.write = mywrite,
};
static int __init myinit(void)
{
int ret;
ret = alloc_chrdev_region ( &mycdevt, MINOR_NUM, MINOR_CNT, "mycdevt");
if(ret<0)
{
printk(KERN_INFO "chardev can't be allocated\n");
// goto label;//todo
}
mycdev = cdev_alloc();//instead of cdev_alloc, we can use cdev_init(&mycdev, &fops);
if(mycdev == NULL)
{
printk(KERN_INFO"cdev_alloc failed\n");
// goto label;//todo
}
mycdev->ops = &fops;
ret = cdev_add(mycdev, mycdevt, 1);
if(ret < 0)
{
printk(KERN_INFO"cdev_add failed\n");
// goto label;//todo
}
myclass = class_create(THIS_MODULE, CLASS_NAME);
if(myclass == NULL)
{
printk(KERN_INFO"class create failed\n");
// goto label;//todo
}
mydevice = device_create(myclass, NULL, mycdevt, NULL, "mydevice");
if(mydevice == NULL)
{
printk(KERN_INFO"device create failed\n");
// goto label;//todo
}
sema_init(sem, 1);//here is the problem
printk(KERN_INFO"myinit done\n");
return 0;
}
static void __exit myexit(void)
{
device_destroy(myclass, mycdevt);
class_unregister(myclass);
class_destroy(myclass);
cdev_del(mycdev);
unregister_chrdev(MAJOR(mycdevt), "mycdevt");
printk(KERN_INFO "exited\n");
}
module_init(myinit);
module_exit(myexit);
I am following ldd3 book, and tried to use simple APIs to use semahore for an app.
What happened is my kernel crashed when it called sema_init function. I read that semaphore is used in mutex mode
http://www.makelinux.net/ldd3/chp-5-sect-3
I also read that semaphore is not a mutex as there is no ownership. I have yet to explore that 'ownership' thing, but for now I am not able to make a simple semaphore.
What wrong I am doing here?
There's no actual semaphore.
This line:
static struct semaphore *sem;
creates a pointer to a semaphore, not a semaphore itself. It's almost certain initialized to NULL.
You probably want something like
static struct semaphore sem;
and therefore
sema_init( &sem, 1);
along with
up( &sem );
and
down( &sem );
Note that these calls are taking the address of an actual semaphore.
I am writing a small kernel module for measuring the time that a network packet takes to exit a node.
This module is a hook in the netfilter library.
For each packet it receives it calculates an hash, gets the tstamp from skbuff and the actual timestamp, and saves all this data in a linked list.
To pass this data to userspace I've created a proc device, and when the user reads from the device I send one of the entries of the linked list.
To make changes to the list (read and write) I have a spinlock. The problem is that sometimes when I read from the proc device while I am processing packets the system crash.
I think that the problem is in the function "dump_data_to_proc", more specifically when try to acquire the spinlock. I've made some tests and it only crashes(softlockup) when running in a tplink router. When I run the module in a "normal" pc(single core) it don't crash,
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/spinlock.h>
#include <net/ipv6.h>
#include <linux/proc_fs.h> /* Necessary because of proc fs */
#include <asm/uaccess.h> /* for copy_from_user */
#include "kmodule_measure_process_time.h"
#include "hash.c"
//DEBUG >=5 is very slow in the tplink
#define DEBUG 2
#define PROCFS_MAX_SIZE 64
#define PROCFS_NAME "measures"
#define MAXIMUM_SAMPLES 10000
static struct nf_hook_ops nfho;
unsigned int total_packets_processed= 0;
unsigned int total_packets_discarded=0;
int temp_counter=0;
struct values_list *HEAD;
spinlock_t list_lock ;
static int hello_proc(struct seq_file *m, void *v) {
seq_printf(m, " stats Mod initialized.\n");
return 0;
}
static int proc_open(struct inode *inode, struct file *file) {
return single_open(file, hello_proc, NULL);
}
ssize_t dump_data_to_proc(struct file *filp, char *buffer, size_t length, loff_t *offset){
int bytesRead = 0;
struct values_list *temp=NULL;
int bytesError=0;
char buff[PROCFS_MAX_SIZE];
spin_lock(&list_lock);
temp=HEAD;
if(temp!=NULL){
HEAD = temp->next;
}
spin_unlock(&list_lock);
if(temp!=NULL){
bytesRead = snprintf(buff, PROCFS_MAX_SIZE ,"%u|%llu|%llu\n", temp->hash,temp->arrival_timestap, temp->exit_timestap);
length = length - bytesRead+1;
kfree(temp);
temp_counter--;
}
bytesError= copy_to_user(buffer, buff, bytesRead);
if(bytesError!=0){
#if DEBUG >0
printk(KERN_INFO "Error: failed to copy to user");
#endif
}
return bytesRead;
}
static const struct file_operations proc_fops = {
.owner = THIS_MODULE,
.open = proc_open,
.read = dump_data_to_proc,
.llseek = seq_lseek,
.release = single_release,
};
static unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
uint32_t hash=0;
ktime_t now_timeval;
struct timespec now;
u64 timestamp_arrival_time=0;
u64 timestamp_now=0;
struct ipv6hdr * ipheader;
struct values_list *node;
int number_of_samples=0;
spin_lock(&list_lock);
number_of_samples=temp_counter;
spin_unlock(&list_lock);
if(number_of_samples > MAXIMUM_SAMPLES){
#if DEBUG > 5
printk(KERN_INFO "Discarded one sample because the list is full.\n");
#endif
total_packets_discarded++; // probably this should be inside a spinlock
return NF_ACCEPT;
}
//calculate arrival time and actual time in ns
timestamp_arrival_time = ktime_to_ns(skb->tstamp);
getnstimeofday(&now);
now_timeval = timespec_to_ktime(now);
timestamp_now = ktime_to_ns(now_timeval);
//get Ipv6 addresses
ipheader = (struct ipv6hdr *)skb_network_header(skb);
hash=simple_hash((char *)&ipheader->saddr,sizeof(struct in6_addr)*2,hash);
total_packets_processed++;
node = (struct values_list *) kmalloc(sizeof(struct values_list),GFP_ATOMIC);
if(!node){
#if DEBUG >0
printk(KERN_INFO "Error cannot malloc\n");
#endif
return NF_ACCEPT;
}
node->hash=hash;
node->arrival_timestap=timestamp_arrival_time;
node->exit_timestap=timestamp_now;
spin_lock(&list_lock);
node->next=HEAD;
HEAD=node;
temp_counter++;
spin_unlock(&list_lock);
return NF_ACCEPT;
}
static int __init init_main(void)
{
nfho.hook = hook_func;
nfho.hooknum = NF_INET_POST_ROUTING;
nfho.pf = PF_INET6;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
#if DEBUG >0
printk(KERN_INFO " kernel module: Successfully inserted protocol module into kernel.\n");
#endif
proc_create(PROCFS_NAME, 0, NULL, &proc_fops);
spin_lock_init(&list_lock);
//Some distros/devices disable timestamping of packets
net_enable_timestamp();
return 0;
}
static void __exit cleanup_main(void)
{
struct values_list *temp;
nf_unregister_hook(&nfho);
#if DEBUG >0
printk(KERN_INFO " kernel module: Successfully unloaded protocol module.\n");
printk(KERN_INFO "Number of packets processed:%d\n",total_packets_processed);
printk(KERN_INFO "Number of packets discarded:%d\n",total_packets_discarded);
#endif
remove_proc_entry(PROCFS_NAME, NULL);
while(HEAD!=NULL){
temp=HEAD;
HEAD= HEAD->next;
kfree(temp);
}
}
module_init(init_main);
module_exit(cleanup_main);
/* * Declaring code as GPL. */
MODULE_LICENSE("GPLv3");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
There are 2 problems with your code:
Use Linux kernel macro for your code. http://makelinux.com/ldd3/chp-11-sect-5 . Just add struct list_head as element to your struct values_list and use list_entry, list_add and other
Netfilter hools are run in softirq context, so you must use spin_lock_irqsave and spin_unlock_irqrestore. This is most likely reason why your system crashes with softlockup. Read carefully http://makelinux.com/ldd3/chp-5-sect-5
I'm trying to write a linux driver. The kernel version is 2.4.18 and the distribution is Red Hat linux 8.0.
The code of my driver is:
#define LINUX
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/fs.h>
#include <asm-i386/semaphore.h>
#include "rng.h"
#include <linux/random.h>
#include <linux/slab.h>
#define DEVICE_NAME "rng"
#define BUF_LEN 80
static int major;
int init_module();
void cleanup_module();
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
struct file_operations my_fops = {
open: device_open,
release: device_release,
};
/* Init and Cleanup */
int init_module() {
SET_MODULE_OWNER(&my_fops);
major = register_chrdev(0, DEVICE_NAME, &my_fops);
return 0;
}
void cleanup_module() {
int ret = unregister_chrdev(major, DEVICE_NAME);
if (ret < 0)
printk("Error in unregister_chrdev: %d\n", ret);
}
static int device_open(struct inode *inode, struct file *file) {
file->f_op=&my_fops;
return 1;
}
static int device_release(struct inode *inode, struct file *file) {
return 0;
}
And the code I'm using in order to test my driver is:
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int openTest() {
int game1 = open("/dev/game1", O_RDONLY); // SEGMENTATION FAULT
int retValue=1;
close(game1);
return retValue;
}
int main() {
int res;
if (openTest() < 1) {
fprintf(stderr, "open didnt work\n");
return -1;
}
fprintf(stderr, "everything works :)\n");
return 0;
}
In the code above, I'm getting a segmentation fault when I'm trying to open the device. Can somebody explain to me why I'm getting this segmentation fault? I really don't understand.
Thanks a lot!
In Linux kernel land, it is convention to return a 0 (zero) when there are no errors. Your device_open() routine is hardcoded to return a 1 (one), which may be causing your segfault.
This Linux Device Drivers book may be helpful to you. The linked edition is written for kernel 2.0.x - 2.4.x, so the information should be appropriate for the dusty and ancient kernel you are using.
This line seems to be wrong file->f_op=&my_fops;
Basically when writing a linux driver operations are setup at build time itself.
when the interrupt occurs in the kernel and If I am reading a timestamp in the kernel. I am reading the timestamp from kernel to the user via procfs. where that interrupt time value will be stored ?? how should the user read that value from the user space ??
ssize_t dev_read(struct file *filp,const char *buf,size_t count,loff_t *offset)
{
if ( count < sizeof(InterruptTime) ) {
// Not enough space provided.
return 0; // Or some error code maybe.
}
if (copy_to_user(buf,&InterruptTime,sizeof(InterruptTime)) {
return -EFAULT;
} else {
return sizeof(InterruptTime); // Number of bytes we copied.
}
}
this is the code I modified in /linuxversion/net/core/dev.c
int netif_rx(struct sk_buff *skb)
{
skb->tstamp = ktime_get_real(); //this will give a timestamp and it will be stored in //skb buffer
//I am calculating a timestamp here. because whenever kernel receive the data then the kernel is
//interrupted and start executing the newly arrived task but I have to read the time when the
//interrupt occurs and get the value of it.
}
but how to copy this value stored in skb->tstamp to procfs driver ??
finally I want to send this timestamp value to the user ??
There is sample proc code and its output
Sample proc code
===============
[root#localhost p]# cat test.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <linux/seq_file.h>
//extern uint64_t interrupt_time;
static struct proc_dir_entry *test_dir;
static int my_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%lu\n", jiffies);
//seq_printf(m, "%lu", interrupt_time);
return 0;
}
static int my_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, my_proc_show, NULL);
}
static const struct file_operations tst_fops = {
.open = my_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init test_init(void)
{
test_dir = proc_mkdir("myproc", NULL);
if (test_dir)
proc_create("jiffies", 0, test_dir, &tst_fops);
return 0;
}
static void __exit test_exit(void)
{
remove_proc_entry ("jiffies", test_dir);
proc_remove (test_dir);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Test");
Output
======
[root#localhost p]# cat /proc/myproc/jiffies
4325737301
I guess you have added this line interrupt_time = skb -> timestamp. If yes, then
Open proc file in kernel space (check fs/proc/ and add an entry for timestamp)
Register your open/read calls.
Whenever user tries to read a file Linux Kernel calls registered read call, in your case it is dev_read.
Check this link for how proc fs is used