Recently I had to write a program to shred a live disk. This was a security requirement for our devices. However, while testing the program, I found that this always failed. It was possible to overwrite whole of the disk except for a single sector. I knew that some process is using this part of the disk and that is the reason I was not able to write to it. I did an lsof for the device when the write operation was going on. There were certain process having files opened from that device. However, even after killing them, my program was not successful in writing the entire disk. Later, I even figured out that the programs with open files were not causing any real problem! But, then what was blocking the overwrite?
Now, we have decided to reboot the machine and do this operation before boot up. However, my doubt stayed till today. It is only today that I came to know about the real culprit. It is none other than the kernel. When a FS is mounted, the disk is opened by kernel. As long as it is mounted, kernel holds this open fd. As mount would have exited long back, so, one will never see this being caused by mount!
My blog on Linux and programming. Covers Linux, VoIP, C, mysql, php and everything else that I come across while tinkering with my Linux boxes.
Showing posts with label Kernel. Show all posts
Showing posts with label Kernel. Show all posts
Sunday, August 15, 2010
Monday, March 8, 2010
Kernel Thread
This post is on how to create a simple kernel thread. Note that the idea here is to explain the kthread and hence not much importance is given to other aspects.
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kthread.h>
struct task_struct *ts;
int my_thread(void *data)
{
printk("%s\n",data);<
while(1)
{
printk("I am a kernel thread\n");
msleep(3000);
if(kthread_should_stop()) return 0;
}
return -1;
}
int tinit(void)
{
ts=kthread_run(my_thread,"message from init","MyKernelThread");
return 0;
}
void tstop(void)
{
kthread_stop(ts);
}
module_init(tinit);
module_exit(tstop);
obj-m := kthread.o
all:
make -C /lib/modules/$(shell uname -r)/build M=`pwd` modules
clean:
@rm -f *.ko *.o *.mod.o *.mod.c
How does it work?
It is very simple. The function kthread_run is not actually a function. It is a macro defined in include/linux/kthread.h. This macro takes care of creating and starting the kernel thread. my_thread is the function that will be run by this thread. All these are very similar to user land threads. However, there is a notable difference here. From the thread function you should keep checking if your thread is being stopped and return. This is done by calling kthread_should_stop(). If this function returns true, that means it is time for us to return. This is a nice feature as this will allow us to do some cleanup before we exit. (This is a must since, if this function does not return, your rmmod will hang). As you can see, the thread is stopped by kthread_stop call. So, what are you waiting for? Have some fun with your brand new kernel thread
kthread.c
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kthread.h>
struct task_struct *ts;
int my_thread(void *data)
{
printk("%s\n",data);<
while(1)
{
printk("I am a kernel thread\n");
msleep(3000);
if(kthread_should_stop()) return 0;
}
return -1;
}
int tinit(void)
{
ts=kthread_run(my_thread,"message from init","MyKernelThread");
return 0;
}
void tstop(void)
{
kthread_stop(ts);
}
module_init(tinit);
module_exit(tstop);
Makefile
obj-m := kthread.o
all:
make -C /lib/modules/$(shell uname -r)/build M=`pwd` modules
clean:
@rm -f *.ko *.o *.mod.o *.mod.c
How does it work?
It is very simple. The function kthread_run is not actually a function. It is a macro defined in include/linux/kthread.h. This macro takes care of creating and starting the kernel thread. my_thread is the function that will be run by this thread. All these are very similar to user land threads. However, there is a notable difference here. From the thread function you should keep checking if your thread is being stopped and return. This is done by calling kthread_should_stop(). If this function returns true, that means it is time for us to return. This is a nice feature as this will allow us to do some cleanup before we exit. (This is a must since, if this function does not return, your rmmod will hang). As you can see, the thread is stopped by kthread_stop call. So, what are you waiting for? Have some fun with your brand new kernel thread
Wednesday, August 13, 2008
Training for Ankit (3)
The zap driver:
1. Used wcfxo.c as the datum
2. Created the following dummy functions
wcfxo_open
wcfxo_close
wcfxo_read
wcfxo_write
wcfxo_hooksig
3. Made the hello_spaninit function to initialize the span
4. Made the zaptel settings as I have shown in the first post in this series
5. Start zaptel service
6. Build and insert module
7. Run ztcfg
8. On the console, dial 1000
9. tail -f /var/log/messages should show message from hooksig
10. On the console, hangup
11. tail -f /var/log/messages should show message from hooksig
12. Since syslog buffers the message and does stuff like "Last message repeated X times" you might not see the second message immediately
#include
#include
#include "zaptel.h"
MODULE_LICENSE("GPL");
extern int gpltest;
struct hpvt {
int pos;
struct zt_span span;
struct zt_chan chan;
char variety[128];
}hello;
static int hello_spanInit();
static int hello_init(void)
{
printk(KERN_ALERT "Before: Hello, world %d \n",gpltest);
hello_spanInit();
printk(KERN_ALERT "After: Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Before: Goodbye, cruel world\n");
zt_unregister(&hello.span);
printk(KERN_ALERT "After: Goodbye, cruel world\n");
}
static int wcfxo_open(struct zt_chan *c)
{
printk(KERN_ALERT "Open called\n");
return 0;
}
static int wcfxo_close(struct zt_chan *c)
{
printk(KERN_ALERT "Close called\n");
return 0;
}
static int wcfxo_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
{
printk(KERN_ALERT "Hooksig called\n");
return 0;
}
static int wcfxo_watchdog(struct zt_span *span, int event)
{
printk("FXO: Restarting DMA\n");
return 0;
}
static int hello_spanInit()
{
struct hpvt *wc=&hello;
strcpy(hello.variety,"Thinvent");
hello.pos=0;
/* Zapata stuff */
sprintf(hello.span.name, "SARIN/%d", wc->pos);
snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
sprintf(wc->chan.name, "SARIN/%d/%d", wc->pos, 0);
snprintf(wc->span.location, sizeof(wc->span.location) - 1,"HERE!");
wc->span.manufacturer = "SARIN";
strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
wc->chan.sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF;
wc->chan.chanpos = 1;
wc->span.chans = &wc->chan;
wc->span.channels = 1;
wc->span.hooksig = wcfxo_hooksig;
// wc->span.irq = wc->dev->irq;
wc->span.open = wcfxo_open;
wc->span.close = wcfxo_close;
wc->span.flags = ZT_FLAG_RBS;
wc->span.deflaw = ZT_LAW_MULAW;
wc->span.watchdog = wcfxo_watchdog;
#ifdef ENABLE_TASKLETS
tasklet_init(&wc->wcfxo_tlet, wcfxo_tasklet, (unsigned long)wc);
#endif
init_waitqueue_head(&wc->span.maintq);
wc->span.pvt = wc;
wc->chan.pvt = wc;
if (zt_register(&wc->span, 0)) {
printk("Unable to register span with zaptel\n");
return -1;
}
return 0;
}
module_init(hello_init);
module_exit(hello_exit);
Make file
obj-m += tzap.o
EXTRA_CFLAGS += -I/root/zaptel/kernel
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
1. Used wcfxo.c as the datum
2. Created the following dummy functions
wcfxo_open
wcfxo_close
wcfxo_read
wcfxo_write
wcfxo_hooksig
3. Made the hello_spaninit function to initialize the span
4. Made the zaptel settings as I have shown in the first post in this series
5. Start zaptel service
6. Build and insert module
7. Run ztcfg
8. On the console, dial 1000
9. tail -f /var/log/messages should show message from hooksig
10. On the console, hangup
11. tail -f /var/log/messages should show message from hooksig
12. Since syslog buffers the message and does stuff like "Last message repeated X times" you might not see the second message immediately
#include
#include
#include "zaptel.h"
MODULE_LICENSE("GPL");
extern int gpltest;
struct hpvt {
int pos;
struct zt_span span;
struct zt_chan chan;
char variety[128];
}hello;
static int hello_spanInit();
static int hello_init(void)
{
printk(KERN_ALERT "Before: Hello, world %d \n",gpltest);
hello_spanInit();
printk(KERN_ALERT "After: Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Before: Goodbye, cruel world\n");
zt_unregister(&hello.span);
printk(KERN_ALERT "After: Goodbye, cruel world\n");
}
static int wcfxo_open(struct zt_chan *c)
{
printk(KERN_ALERT "Open called\n");
return 0;
}
static int wcfxo_close(struct zt_chan *c)
{
printk(KERN_ALERT "Close called\n");
return 0;
}
static int wcfxo_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
{
printk(KERN_ALERT "Hooksig called\n");
return 0;
}
static int wcfxo_watchdog(struct zt_span *span, int event)
{
printk("FXO: Restarting DMA\n");
return 0;
}
static int hello_spanInit()
{
struct hpvt *wc=&hello;
strcpy(hello.variety,"Thinvent");
hello.pos=0;
/* Zapata stuff */
sprintf(hello.span.name, "SARIN/%d", wc->pos);
snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
sprintf(wc->chan.name, "SARIN/%d/%d", wc->pos, 0);
snprintf(wc->span.location, sizeof(wc->span.location) - 1,"HERE!");
wc->span.manufacturer = "SARIN";
strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
wc->chan.sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF;
wc->chan.chanpos = 1;
wc->span.chans = &wc->chan;
wc->span.channels = 1;
wc->span.hooksig = wcfxo_hooksig;
// wc->span.irq = wc->dev->irq;
wc->span.open = wcfxo_open;
wc->span.close = wcfxo_close;
wc->span.flags = ZT_FLAG_RBS;
wc->span.deflaw = ZT_LAW_MULAW;
wc->span.watchdog = wcfxo_watchdog;
#ifdef ENABLE_TASKLETS
tasklet_init(&wc->wcfxo_tlet, wcfxo_tasklet, (unsigned long)wc);
#endif
init_waitqueue_head(&wc->span.maintq);
wc->span.pvt = wc;
wc->chan.pvt = wc;
if (zt_register(&wc->span, 0)) {
printk("Unable to register span with zaptel\n");
return -1;
}
return 0;
}
module_init(hello_init);
module_exit(hello_exit);
Make file
obj-m += tzap.o
EXTRA_CFLAGS += -I/root/zaptel/kernel
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
Tuesday, August 12, 2008
Training for Ankit (2)
Ok, we built the kernel module. What do we do with it now?
1. Insert the kernel module to kernel
insmod tzap.ko
2. See the messages appearing in /var/log/messages
At this point, Ankit asked me why tail /var/log/messages? Why can't we see that directly?
Ans: Insmod calls the hello_init function. The message comes from
printk(KERN_ALERT "Before: Hello, world %d \n",gpltest);
Now, KERN_ALERT is a priority for kernel messages. ALERT is not a high priority so that the message comes on our Terminal. We changed the line to
printk(KERN_EMERG "Before: Hello, world %d \n",gpltest);
This time, the message appeared on the Terminal. I then showed him /etc/syslog.conf and told him that, it is syslog which reads these messages and decides what to do with it. I showed him my /etc/syslog.conf and explained how various messages are destined to go to various locations.
3. Unloading the module
This is done with the command rmmod tzap. hello_exit is called when this happens.
4. Module license line.
MODULE_LICENSE("GPL"); or something like that tells the module is licensed under GPL license. This has an important for our customer. They will have to GPL the code if they plan to access the symbols that are exported using EXPORT_SYMBOL_GPL. Anyway, they are lucky and zaptel does not have GPL exports.
5. Init & Exit
module_init and module_exit defines the entry points for insmod and rmmod.
6. One more step __init and __exit
These macros tell the kernel that the functions thus defined are specific to module loading and unloading. I told him to remember the Linux boot process and the line "Freeing unused kernel memory". This is possible because if I mark a function as __init, the kernel knows it has no need of the function after initialization. This allows the kernel to free some memory after boot-up
1. Insert the kernel module to kernel
insmod tzap.ko
2. See the messages appearing in /var/log/messages
At this point, Ankit asked me why tail /var/log/messages? Why can't we see that directly?
Ans: Insmod calls the hello_init function. The message comes from
printk(KERN_ALERT "Before: Hello, world %d \n",gpltest);
Now, KERN_ALERT is a priority for kernel messages. ALERT is not a high priority so that the message comes on our Terminal. We changed the line to
printk(KERN_EMERG "Before: Hello, world %d \n",gpltest);
This time, the message appeared on the Terminal. I then showed him /etc/syslog.conf and told him that, it is syslog which reads these messages and decides what to do with it. I showed him my /etc/syslog.conf and explained how various messages are destined to go to various locations.
3. Unloading the module
This is done with the command rmmod tzap. hello_exit is called when this happens.
4. Module license line.
MODULE_LICENSE("GPL"); or something like that tells the module is licensed under GPL license. This has an important for our customer. They will have to GPL the code if they plan to access the symbols that are exported using EXPORT_SYMBOL_GPL. Anyway, they are lucky and zaptel does not have GPL exports.
5. Init & Exit
module_init and module_exit defines the entry points for insmod and rmmod.
6. One more step __init and __exit
These macros tell the kernel that the functions thus defined are specific to module loading and unloading. I told him to remember the Linux boot process and the line "Freeing unused kernel memory". This is possible because if I mark a function as __init, the kernel knows it has no need of the function after initialization. This allows the kernel to free some memory after boot-up
Training for Ankit (1)
Today I was at customers development centre. Ankit is to develop the driver for the hardware they develop. This post will record the session that I had with Ankit.
Ankit was new to kernel programming. Even I have not mastered this beast well. Neverthless, I got Ankit started with it.
1. Zaptel discussion
It is not necessary to define a span in case of an FXS/FXO. Just need to define a channel.
However, for registering fxs/fxo also, we pass a span argument to zaptel. I asked Ankit to look at span as an abstraction for a device (E1 card, FXS etc) which 'n' channels. (n = 1, for FXS)
I showed him how to define a fxo channel.
zaptel.conf
loadzone = us
defaultzone = us
fxsks=1
zapata.conf (Additions only)
signalling=fxs_ks
callerid="Green Phone"<(256) 428-6121>
channel => 1
extensions.conf additions
exten => 1000,1,Dial(Zap/1)
2. Kernel module programming
To program kernel modules, you need to have kernel source for your current kernel.
I asked him to first download LDD3.
Then, we copied the code from second chapter and compiled the module.
This had to be done on my laptop, as he did not have kernel sources installed on his system.
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
Then we created the makefile
obj-m += tzap.o
EXTRA_CFLAGS += -I/root/zaptel/kernel
all:
make -C /lib/modules/$(shell uname -r)/build M=`pwd` modules
With the make file in place, we compiled the module and inserted it.
Ankit was new to kernel programming. Even I have not mastered this beast well. Neverthless, I got Ankit started with it.
1. Zaptel discussion
It is not necessary to define a span in case of an FXS/FXO. Just need to define a channel.
However, for registering fxs/fxo also, we pass a span argument to zaptel. I asked Ankit to look at span as an abstraction for a device (E1 card, FXS etc) which 'n' channels. (n = 1, for FXS)
I showed him how to define a fxo channel.
zaptel.conf
loadzone = us
defaultzone = us
fxsks=1
zapata.conf (Additions only)
signalling=fxs_ks
callerid="Green Phone"<(256) 428-6121>
channel => 1
extensions.conf additions
exten => 1000,1,Dial(Zap/1)
2. Kernel module programming
To program kernel modules, you need to have kernel source for your current kernel.
I asked him to first download LDD3.
Then, we copied the code from second chapter and compiled the module.
This had to be done on my laptop, as he did not have kernel sources installed on his system.
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
Then we created the makefile
obj-m += tzap.o
EXTRA_CFLAGS += -I/root/zaptel/kernel
all:
make -C /lib/modules/$(shell uname -r)/build M=`pwd` modules
With the make file in place, we compiled the module and inserted it.
- obj-m is a variable understood by kernel build system
- obj-m = tzap.o indicates that the name of your module source file is tzap.c
- EXTRA_CFLAGS defines the extra compile time flags specific for your module
- In this case that extra flag is not really necessary. But as we do more work with this driver, we will need it.
- Make command arguments: -C
Tells the make to change to before actually running - Make command arguments: M=`pwd`defines M, which will be used by kernel build system to determine the directory in which module source is present
- Make command arguments: modules is the target to build
Subscribe to:
Posts (Atom)