How to accelerate Reading/Writing Attribute Data? - linux

I used File attributes in the sys filesystem which allow userspace to communicate with the driver using SysFS. The problem is that I have much data to be transfered so I lost much time. This is a very slow process!
In the kennel module I have this part of the code:
static DEVICE_ATTR(writeFile,S_IWUSR,NULL,writeFunction);
static DEVICE_ATTR(resultFile,S_IRUSR, readFunction, NULL);
static ssize_t writeFunction(struct device *dev, struct device_attribute *attr,
const char * buf, size_t count) {
if(count >0){
resp_ready = 1;
sscanf(buf,"%2x,",&src_vect[0]);
for (i=0;i<80;i++)
{
sscanf(buf+3+12*i,"%2x,%2x,%2x,%2x,",&src_vect[4*i+1],&src_vect[4*i+2],&src_vect[4*i+3],&src_vect[4*i+4]);
}
.
.
.
}
static ssize_t readFunction(struct device *dev, struct device_attribute *attr, char *buf) {
//write the result to buf
for (i=0;i<6;i++)
{
sprintf(buf+72*i,"%8x,%8x,%8x,%8x,%8x,%8x,%8x,%8x,",dst_f[8*i],dst_f[8*i+1],dst_f[8*i+2],dst_f[8*i+3],dst_f[8*i+4],dst_f[8*i+5],dst_f[8*i+6],dst_f[8*i+7]);
}
.
.
.
}
How can I reduce data transfer time from/to user/kennel space?
Is there any method faster than this one?

Related

Kernel throws error while writing to the character device file in 4.9.82-ti-r102 debian 9.3

I created the device file under /dev folder successfully, but writing to that device file makes kernel to throw following error messages.
kernel:[10090.943733] Internal error: : 1b [#3] PREEMPT SMP ARM
kernel:[10091.049020] Process echo (pid: 3728, stack limit = 0xdc40a218)
kernel:[10091.054880] Stack: (0xdc40be60 to 0xdc40c000)
kernel:[10091.059267] be60: c15491c6 00000022 dc5cb14c bf30430c dc40bedc dc40be88 c075312c c074fe5c
kernel:[10091.067488] be80: c0753018 ffffff04 ffff0a00 c140414c c0d407c8 bf30430c c140414c 40cfbcf3
kernel:[10091.075709] bea0: 00852878 ffffff04 ffff0a00 00040952 c01a7404 c140414c 00852878 00852878
Segmentation fault
I know very basic of Linux Device Drivers
can anyone help me regarding this??
I'm attaching the code for this character device driver
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/uaccess.h>
#include<linux/device.h>
MODULE_AUTHOR("RUCHA");
MODULE_DESCRIPTION("Character Driver First test");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.1");
static int MajorNum;
static struct class* RetValOfClassRegistration = NULL;
static struct device* RetVal = NULL;
static char message[1024];
static int openDev(struct inode * , struct file *);
static int closeDev(struct inode * , struct file *);
static ssize_t readDev(struct file *, char *, size_t, loff_t *);
static ssize_t writeDev(struct file *, const char *, size_t, loff_t *);
static struct file_operations FileOps = {
.owner = THIS_MODULE,
.open = openDev,
.read = readDev,
.write = writeDev,
.release = closeDev,
};
static int registerCharDev(void){
return register_chrdev(0,"MyDev",&FileOps);
}
static int __init Loaded(void){
// registering device
MajorNum = registerCharDev();
if(MajorNum < 0){
printk("Can not register device\n");
return -1;
}
printk("Driver Loaded with %d \n",MajorNum);
// registering device class
RetValOfClassRegistration = class_create(THIS_MODULE,"MyCharacterDriver");
if(RetValOfClassRegistration < 0){
printk("can not register class for driver number : %d\n",MajorNum);
return 0;
}
// register the driver
RetVal = device_create(RetValOfClassRegistration,NULL,MKDEV(MajorNum,0),NULL,"MyDev");
return 0;
}
static void __exit Removed(void){
device_destroy(RetValOfClassRegistration,MKDEV(MajorNum,0));
class_unregister(RetValOfClassRegistration);
class_destroy(RetValOfClassRegistration);
unregister_chrdev(MajorNum,"MyDev");
printk("Driver Removed\n");
}
module_init(Loaded);
module_exit(Removed);
static int openDev(struct inode *inodep , struct file *filep){
printk("Device is now open to read write operations\n");
return 0;
}
static int closeDev(struct inode *inodep , struct file *filep){
printk("Device Closed\n");
return 0;
}
static ssize_t readDev(struct file *filep, char *c, size_t v, loff_t *lp){
printk("Read From the device\n");
return 0;
}
static ssize_t writeDev(struct file *file, const char __user *buf, size_t count, loff_t *offset)
{
sprintf(message, "%s(%zu letters)", buf, len);
return 0;
}
and the user input is
echo '1' > /dev/MyDev
You can't access a user data pointer (buf) directly. You need to use copy_from_user to copy the data into kernel memory first. Also, use snprintf instead of sprintf to avoid buffer overflows.
Also, compile with debugging enabled, especially CONFIG_DEBUG_INFO, to get more helpful error messages in the kernel log.

Null pointer exception in kernel while doing write operation

I am a windows driver programmer, who is also a complete beginner in linux kernel development. im trying out simple linux kernel modules.
I have written a parallel port driver as in the following code and could successfully load this driver.
I have created a char device node using command mknod with same major and minor numbers as in the code. I have tried reading from the file using cat command and i found it was working fine. While i tried writing the same device using command cat in.txt>/dev/parallel_dev the prompt shows a message "killed" and in dmesg, it has shown unable to handle kernel NULL pointer exception.
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h> //kprintf
#include<linux/module.h> //kmalloc
#include<linux/types.h>
#include<linux/fs.h> //fileoperations,register_chrdev
#include<linux/slab.h>
#include<linux/uaccess.h> //copy from/to user
#include<linux/ioport.h> //check_region
#include<linux/interrupt.h>
#include<linux/delay.h>
static int parallel_open(struct inode* p_node, struct file* p_file);
static int parallel_release(struct inode* p_node, struct file* p_file);
static ssize_t parallel_read(struct file* p_file, char* buf, size_t count, loff_t* f_pos);
static ssize_t parallel_write(struct file* p_file, const char* buf, size_t count, loff_t* f_pos);
static irqreturn_t parallel_interrupt(int irq,void* dev);
static const int major_no = 709;
static const char* dev_name = "parallel_tryout";
#define par_base 0x378
int port;
int* parallel_buffer;
struct file_operations fops = {
.read = parallel_read,
.write = parallel_write,
.open = parallel_open,
.release = parallel_release,
};
static int parallel_init(void)
{
int reg_result;
int irq_req_result;
unsigned int irq_num = 7;
printk("Entered init");
printk("Initializing parallelport dev with major %d",major_no);
reg_result = register_chrdev(major_no, dev_name, 0);
if(reg_result < 0 )
{
printk("Error registering char dev: %s",dev_name);
}
parallel_buffer = kmalloc(16,GFP_KERNEL);
if(parallel_buffer==NULL)
{
printk("Error allocating memory for: %s",dev_name);
}
printk("Port registration");
request_region(0x378,1,"parallelport");
if(port)
{
printk("Error allocating port");
}
parallel_buffer = inb(par_base);
if(parallel_buffer != NULL)
{
printk("Allocated buffer");
}
irq_req_result = request_irq(irq_num,parallel_interrupt,IRQF_SHARED,dev_name,parallel_buffer);
return 0;
}
static void parallel_exit(void)
{
unregister_chrdev(major_no, dev_name);
release_region(0x378,1);
}
static int parallel_open(struct inode* p_node, struct file* p_file)
{
printk("parallel driver opened from device: %s",dev_name);
return 0;
}
static int parallel_release(struct inode* p_node, struct file* p_file)
{
printk("Memory driver closed from device: %s",dev_name);
return 0;
}
static ssize_t parallel_read(struct file* p_file, char* buf, size_t count, loff_t* f_pos)
{
copy_to_user(buf,parallel_buffer,1);
printk("Copied data:%s ",buf);
printk("Memory driver read from device: %s",dev_name);
return 0;
}
static ssize_t parallel_write(struct file* p_file, const char* buf, size_t count, loff_t* f_pos)
{
copy_from_user(parallel_buffer,buf,1);
printk("Copied data:%s ",parallel_buffer);
printk("Memory driver written from device: %s",dev_name);
return 0;
}
static irqreturn_t parallel_interrupt(int irq,void* dev)
{
irqreturn_t return_value;
printk("parallel interrupt detected!!!!");
return return_value;
}
module_init(parallel_init);
module_exit(parallel_exit);
what could be the possible reason for this, and thanks in advance.

How to capture network frames in a kernel module

I want to capture frames when they're received by a certain NIC; extract some information from them(currently I need to capture the source MAC and source IP addresses); save these information in some public data structure; and let the frame go up in its way to the TCP/IP stack.
I've used Netfilter before, but apparently it doesn't provide Link layer hooks.
Is there any way I can do this?
I am writing this as a Kernel Module; running Linux kernel 2.6.32
Actually Netfilter should work fine because it receives the entire packet (internally stored as an sk_buff which includes the Link layer information). Here's some sample code that should get you started. This code intercepts all incoming packets for a given device and prints the src MAC and src IP.
static struct nf_hook_ops nfin;
static unsigned int hook_func_in(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct ethhdr *eth;
struct iphdr *ip_header;
/* check *in is the correct device */
if (in is not the correct device)
return NF_ACCEPT;
eth = (struct ethhdr*)skb_mac_header(skb);
ip_header = (struct iphdr *)skb_network_header(skb);
printk("src mac %pM, dst mac %pM\n", eth->h_source, eth->h_dest);
printk("src IP addr:=%d.%d.%d.%d:%d\n", NIPQUAD(ip_headr->saddr));
return NF_ACCEPT;
}
static int __init init_main(void)
{
nfin.hook = hook_func_in;
nfin.hooknum = NF_IP_LOCAL_IN;
nfin.pf = PF_INET;
nfin.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfin);
return 0;
}
static void __exit cleanup_main(void)
{
nf_unregister_hook(&nfin);
}
module_init(init_main);
module_exit(cleanup_main);

Getting list of network devices inside the Linux kernel

I've been looking through net/core/dev.c and other files to try to find out how to get the list of network devices that are currently configured and it's proving to be a little difficult to find.
The end goal is to be able to get network device statistics using dev_get_stats in dev.c, but I need to know the current interfaces so I can grab the net_device struct to pass in. I'm having to do this inside the kernel as I'm writing a module which adds in a new /proc/ entry which relates to some statistics from the current network devices so from what I can gather this must be done inside the kernel.
If someone could point me to how to get the interfaces it would be much appreciated.
This ought to do the trick:
#include <linux/netdevice.h>
struct net_device *dev;
read_lock(&dev_base_lock);
dev = first_net_device(&init_net);
while (dev) {
printk(KERN_INFO "found [%s]\n", dev->name);
dev = next_net_device(dev);
}
read_unlock(&dev_base_lock);
Given a struct net *net identifying the net namespace that you are interested in, you should grab the dev_base_lock and use for_each_netdev():
read_lock(&dev_base_lock);
for_each_netdev(net, dev) {
/* Inspect dev */
}
read_unlock(&dev_base_lock);
(In newer kernels, you can use RCU instead, but that is probably an overcomplication in this case).
To obtain the net namespace to use, you should be registering your proc file with register_pernet_subsys():
static const struct file_operations foostats_seq_fops = {
.owner = THIS_MODULE,
.open = foostats_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = foostats_seq_release,
};
static int foo_proc_init_net(struct net *net)
{
if (!proc_net_fops_create(net, "foostats", S_IRUGO,
&foostats_seq_fops))
return -ENOMEM;
return 0;
}
static void foo_proc_exit_net(struct net *net)
{
proc_net_remove(net, "foostats");
}
static struct pernet_operations foo_proc_ops = {
.init = foo_proc_init_net,
.exit = foo_proc_exit_net,
};
register_pernet_subsys(&foo_proc_ops)
In your foostats_seq_open() function, you take a reference on the net namespace, and drop it in the release function:
static int foostats_seq_open(struct inode *inode, struct file *file)
{
int err;
struct net *net;
err = -ENXIO;
net = get_proc_net(inode);
if (net == NULL)
goto err_net;
err = single_open(file, foostats_seq_show, net);
if (err < 0)
goto err_open;
return 0;
err_open:
put_net(net);
err_net:
return err;
}
static int foostats_seq_release(struct inode *inode, struct file *file)
{
struct net *net = ((struct seq_file *)file->private_data)->private;
put_net(net);
return single_release(inode, file);
}
The foostats_seq_show() function can then obtain the net, walk the devices, gather the statistics and produce the output:
static int sockstat6_seq_show(struct seq_file *seq, void *v)
{
struct net *net = seq->private;
struct net_device *dev;
int foostat, barstat;
read_lock(&dev_base_lock);
for_each_netdev(net, dev) {
/* Inspect dev */
}
read_unlock(&dev_base_lock);
seq_printf(seq, "Foo: %d\n", foostat);
seq_printf(seq, "Bar: %d\n", barstat);
return 0;
}

how can I determine a network device speed from a linux kernel module

I have a linux kernel module that needs to find the speed of a given network interface (i.e. "eth0"). For linux 2.6.31 how would I find the speed (configured/negotiated)?
Every network driver has a "ethtool" implementation for such features. But you probably need a generic function that can give you the speed for a generic netdev struct. You can have a look at net/core/net-sysfs.c and see how it implements the /sys/class/net interface. For example :
static ssize_t show_speed(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *netdev = to_net_dev(dev);
int ret = -EINVAL;
if (!rtnl_trylock())
return restart_syscall();
if (netif_running(netdev) &&
netdev->ethtool_ops &&
netdev->ethtool_ops->get_settings) {
struct ethtool_cmd cmd = { ETHTOOL_GSET };
if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd));
}
rtnl_unlock();
return ret;
}

Resources