2

カーネルモジュールの読み取り関数でcopy_to_userを使用しようとしましたが、カーネルからユーザーバッファにデータをコピーできません。私が何か間違いをしているのなら、誰か教えてもらえますか?私のカーネルバージョンは2.6.35です。カーネルモジュールの一部と、それをテストするために使用されているアプリケーションを紹介します。今のところ私の焦点は、このcopy_to_userが機能しない理由です。どんな助けでも素晴らしいでしょう。

///////////////////////////////////kernel module//////////////////////////////////////

#define BUF_LEN 80

static char msg[BUF_LEN];       
static char *msg_Ptr;

static int device_open(struct inode *inode, struct file *file)
{
static int counter = 0;

if (Device_Open)
    return -EBUSY;

Device_Open++;
printk(KERN_ALERT "In open device call\n");

sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);

return SUCCESS;
}


static ssize_t device_read(struct file *filp,    
           char __user *buffer,    
           size_t length,    
           loff_t * offset)
{
/*
 * Number of bytes actually written to the buffer 
 */
int bytes_read = 0;

/*
 * If we are at the end of the message, 
 * return 0 signifying end of file 
 */
if (*msg_Ptr == 0)
    return 0;

/* 
 * Actually put the data into the buffer 
 */


else {
    bytes_read=copy_to_user(buffer, msg, length);
    if (bytes_read==-1);
        {
         printk(KERN_INFO "Error in else while copying the data \n");
        }

    }

   return bytes_read;
}






////////////////////////////////////////application////////////////////////
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> 
#include <stdlib.h>

#define  BUF_SIZE    40

int main()
{
ssize_t num_bytes;
int fd, n=0;
char buf[BUF_SIZE];

fd=open("/dev/chardev", O_RDWR);
if(fd== -1){perror("Error while opening device");exit(1);}

printf("fd=%d\n",fd);
num_bytes=read(fd, buf, BUF_SIZE);
if(num_bytes==-1){perror("Error while reading"); exit(2);}

printf("The value fetched is %lu bytes\n", num_bytes);

while(n<=num_bytes)
    {
        printf("%c",buf[n]);
        n++;
    }

close(fd);
return 0;

}
4

2 に答える 2

2

作成したコードスニペットにはいくつかの問題があります。まず、呼び出しを行うのは良いことではありません。try_module_get(THIS_MODULE);
このステートメントは、モジュール自体のモジュールのrefcountを増やしようとします。代わりに、 file_ops構造体のownerフィールドをinitメソッドでに設定する必要があります。このように、参照処理はモジュールコードの外部のVFSレイヤーで行われます。Linuxカーネルモジュール:try_module_get/module_putをいつ使用するかをご覧ください。 次に、Vineetが述べたように、file_opsフィールドからポインターを取得する必要があります。 THIS_MODULE
private_data

最後になりましたが、エラーが発生したように見える理由は次のとおりです...実際には...発生しませんでした:copy_to_user必要なすべてのバイトが宛先メモリ領域に正常にコピーされ、厳密に正の場合、呼び出しは0を返しますエラーの場合にコピーされなかったバイト数を示す値。そうは言っても、あなたが走るとき:

/* Kernel part */
bytes_read=copy_to_user(buffer, msg, length);
/* 
 * Wrong error checking :
 * In the below statement, "-1" is viewed as an unsigned long.
 * With a simple equality test, this will not bother you
 * But this is dangerous with other comparisons like "<" or ">"
 * (unsigned long)(-1) is at least 2^32 - 1 so ...
 */
if (-1 == bytes_read) {
    /* etc. */
}
return bytes_read;

/* App part */
num_bytes=read(fd, buf, BUF_SIZE);
/* etc.. */
while(n<=num_bytes) {
    printf("%c",buf[n]);
    n++;
}

コピーが成功すると、1文字だけを取得する必要があります。これは、あなたの場合は1つの「I」だけです。さらに、msg_Ptrポインターを保護手段として使用しますが、更新することはありません。これにより、への呼び出しが間違ってしまう可能性がありcopy_to_userます。
copy_to_userを呼び出してユーザースペースポインターをチェックしますaccess_okが、カーネルスペースポインターと指定された長さが正しくない場合、これはKernel Oops/Panicで終了する可能性があります。

于 2013-01-24T13:07:49.033 に答える
0

開いた状態でfile->private_dataを更新してから、構造体でそれをフェッチする必要があると思います。msgバッファ(カーネルバッファ)が適切な参照を取得していないと思います。

于 2013-01-24T07:43:43.237 に答える