views:

1825

answers:

4

I know all the discussions about why one should not read/write files from kernel, instead how to use /proc or netlink to do that. I want to read/write anyway. I have also read http://www.linuxjournal.com/article/8110

However, problem is 2.6.30 does not export sys_read(). Rather its wrapped in SYSCALL_DEFINE3. So if I use that in my module, I get following warnings: WARNING: "sys_read" [xxx.ko] undefined! WARNING: "sys_open" [xxx.ko] undefined!

Obviously insmod cannot load the module because linking does not happen correctly.

Questions:

  • How to read/write within kernel after 2.6.22 (where sys_read()/sys_open() are not exported)?
  • In general, how to use system calls wrapped in macro SYSCALL_DEFINEn() from within the kernel?
+10  A: 

You should be aware that that you should avoid file I/O when possible. The main idea is to go "one level deeper" and call VFS level functions instead of the syscall handler directly:

Includes:

#include <linux/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>

Opening a file (similar to open):

struct file* file_open(const char* path, int flags, int rights) {
    struct file* filp = NULL;
    mm_segment_t oldfs;
    int err = 0;

    oldfs = get_fs();
    set_fs(get_ds());
    filp = filp_open(path, flags, rights);
    set_fs(oldfs);
    if(IS_ERR(filp)) {
     err = PTR_ERR(filp);
     return NULL;
    }
    return filp;
}

Close a file (similar to close):

void file_close(struct file* file) {
    filp_close(file, NULL);
}

Reading data from a file (similar to pread):

int file_read(struct file* file, unsigned long long offset, unsigned char* data, unsigned int size) {
    mm_segment_t oldfs;
    int ret;

    oldfs = get_fs();
    set_fs(get_ds());

    ret = vfs_read(file, data, size, &offset);

    set_fs(oldfs);
    return ret;
}

Writing data to a file (similar to pwrite):

int file_write(struct file* file, unsigned long long offset, unsigned char* data, unsigned int size) {
    mm_segment_t oldfs;
    int ret;

    oldfs = get_fs();
    set_fs(get_ds());

    ret = vfs_write(file, data, size, &offset);

    set_fs(oldfs);
    return ret;
}

Syncing changes a file (similar to fsync):

int file_sync(struct file* file) {
    file_fsync(file, file->f_dentry, 0);
    return 0;
}
dmeister
Thank you. I was thinking to do something similar by replicating sys_read/sys_open functionality. But this is great help. A curiosity, is there any way to use system calls declared using SYSCALL_DEFINE?
Methos
I tried this code in kernel 2.6.30 (Ubuntu 9.04) and reading the file crashes the system. Anyone experienced the same issue?
Enrico Detoma
@Enrico Detoma? Oh, wow. This there any way that you can give me the module you used? Never seen that before?
dmeister
A: 

/home/rasto/Desktop/lwnfs/lwnfs_simpler.c: In function ‘file_write’: /home/rasto/Desktop/lwnfs/lwnfs_simpler.c:280: error: ‘byte’ undeclared (first use in this function)

rasar
I updates the answer accordingly.
dmeister
A: 

/home/rasto/Desktop/lwnfs/lwnfs_simpler.c: In function ‘file_write’: /home/rasto/Desktop/lwnfs/lwnfs_simpler.c:280: error: ‘byte’ undeclared (first use in this function)<<

Change byte* into unsigned char*

Volodymyr M. Shcherbyna
I updates the answer accordingly.
dmeister
A: 

thanq you...very much for ur support it was really very helpful.

dev