Hi All,
I was trying to copy a data from kernel memory to user space memory but it didnot work. I dont know the mistake i am doing.
#mknod /dev/myown1 c 256 4
#chmod 666 myown1
#cat myown1
#
Before doing the above i loaded my module.
Driver code is below.
driver.c
---------
#include
#include
#include
#include
#include
static int sample_open(struct inode *inode, struct file* filp);
static int sample_read(struct file* filep, char* data,int len,loff_t *off);
struct file_operations rwstruct={
open:sample_open,
read:sample_read,
owner:THIS_MODULE
};
static int major;
char *memory;
int init_module(void)
{
printk(KERN_EMERG "Inside init module \n");
major = register_chrdev(256,"myown1",&rwstruct);
printk(KERN_EMERG "Major number is %d\n",major);
memory = kmalloc(10,GFP_KERNEL);
memset(memory,0,10);
return 0;
}
void cleanup_module(void)
{
printk(KERN_EMERG "Inside cleanup\n");
unregister_chrdev(256,"myown1");
kfree(memory);
}
static int sample_open(struct inode *inode,struct file* filep)
{
printk(KERN_EMERG "Inside sample_open \n");
int type = MINOR(inode->i_rdev);
printk(KERN_EMERG "Minor number is %d\n",type);
return 0;
}
static int sample_read(struct file* filep, char* data,int len, loff_t *off)
{
printk(KERN_EMERG "Inside sample_read lenght is %d: \n",len);
copy_to_user(data,"MANI",2);
// copy_to_user(data,memory,3); I did this also.didnt work
return 0;
}
Whenever i do cat /dev/myown1 i couldnot see any characters getting displayed. All my kernel messages in read are getting displayed in /var/log/messages.
Please can someone help me understand the copy_to_user function usage.
Thanks in advance
- mani
[header files are not getting displayed]
Strace o/p: further reference.
strace cat /dev/myown1
execve("/bin/cat", ["cat", "/dev/myown1"], [/* 21 vars */]) = 0
brk(0) = 0x9828000
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f26000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=141008, ...}) = 0
old_mmap(NULL, 141008, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f03000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\n\257m"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1489572, ...}) = 0
old_mmap(0x6c6000, 1219548, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x6c6000
old_mmap(0x7ea000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x124000) = 0x7ea000
old_mmap(0x7ee000, 7132, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ee000
close(3) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f02000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7f026c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0x7ea000, 8192, PROT_READ) = 0
mprotect(0x6be000, 4096, PROT_READ) = 0
munmap(0xb7f03000, 141008) = 0
brk(0) = 0x9828000
brk(0x9849000) = 0x9849000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=48504432, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7d02000
close(3) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
open("/dev/myown1", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(0, 4), ...}) = 0
read(3, "", 4096) = 0
close(3) = 0
close(1) = 0
exit_group(0) = ?
You need to return the
You need to return the amount of data written in sample_read(), not 0...
<pre> - HTML, do you speak it?
returned amount of data read, but cat of the file runs infinetly
i changed the read function like below.
static int sample_read(struct file* filep, char* data,int len, loff_t *off)
{
printk(KERN_EMERG "Inside sample_read lenght is %d: \n",len);
copy_to_user(data,"memory",2);
return 2;
}
I changed the return value to 2 , but when i do cat /dev/myown1 device the o/p runs infinetly on the screen. Couldnot get how the return value is mapped to the characters displayed when cat for a device file is executed.
thanks in advance.
Thanks & Regards,
Mani
Well, what did you expect?
Well, what did you expect? Whenever someone tries to read from the device, it always returns 2 bytes.
You're obviously not very familiar with the basic read() syscall, and how programs like /bin/cat use it, so I'd suggest you read the read(2) man page. Pay close attention to the "return value" section of the man page. Your kernel module always returns 2 -- perhaps that is not what you want.
What i was trying to do is
What i was trying to do is
1) Get a string from user using a small user program and write it into the device(myown1) (Maximum of 10 characters).
2) When cat of the device(myown1) is did it should display the string entered by the user.
In doing above i could store the string in the kernel memory through a char pointer in kernel space.( copy_from_user call i used in write method). In read function i used copy_to_user from the char pointer.
I even returned the third parameter in the read function call( which is the length to be read from the fd)
Everything worked fine when i executed a small user program to read 3/4/ till 7 characters from that file and i could print the string.
When i do cat /dev/myown1 then i am not getting the string.
There are few mistakes my read function is doing.
I checked the strace o/p of cat program for a simple file and the final calls of the o/p showed
1) read(3,"#include \n#include \n#include
No. The final read() syscall
No. The final read() syscall for a strace will show (assuming no errors, etc):
read() returns 0 to indicate EOF (end of file). Your device does not. Your device also fails to handle the case where you perform a partial read (such as reading 1 byte at a time), and you need to update the value the *off pointer points to.
Untested code:
static int sample_read(struct file *filep, char *data, int len, loff_t *off) { const char *msg = "Your message here."; const int msg_len = strlen(msg); if (*off >= msg_len) return 0; /* EOF */ if (*off + len >= msg_len) len = msg_len - *off; copy_to_user(data, msg + *off, len); *off += len; return len; }Additionally, you need to handle the case where you change the message while someone is still reading it, however unlikely it is. How you deal with this is up to you.