x64 上の Linux 3.10.45 用のカーネル モジュール (ハードウェアのストレス テスト ツール) を構築しようとしています。これまでのところ、ミューテックスを追加するまでは問題なく動作しているように見えました。
関数を使用してミューテックスを追加し、mutex_init、mutex_lock、mutex_unlock、mutex_destroy を追加しました。
モジュールをビルドしてもエラーや警告は発生しませんでしたが、「insmod」でロードすると、dmesg にエラー メッセージが表示されます。
[76603.744551] tryBlk: Unknown symbol mutex_lock_nested (err 0)
[76603.744574] tryBlk: Unknown symbol mutex_destroy (err 0)
「不明なシンボル」の場合、MODULE_LICENSE("GPL v2") 行を追加すると役立つ場合があるというヒントを見つけました。
変わりはない。
linux/mutex.h を見ると、シンボル CONFIG_DEBUG_LOCK_ALLOC が定義されている場合にのみ、mutex_lock が mutex_lock_nested に定義されることがわかりました。これを確認すると、私の .config で定義されているようです。(触ったことを覚えていません。基本的には、kernel.org からビルドされた単なるカーネルです)。
これに問題はありますか?このデバッグ機能を使用してモジュールをビルドするには、モジュールに何か他のものを手動で追加する必要がありますか?
インクルード ファイルとシーケンスを変更しようとしました。変わりはない。
システムは Debian-7 'Wheezy' x64 を実行しており、カーネルは 3.10.45 に変更されています。
ミューテックスを使用するファイル:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include "ring.h"
struct RingBuf
{
unsigned char *buffer;
unsigned int size;
unsigned int inp,outp;
struct mutex mtx;
};
static int _bytesavail(struct RingBuf *self);
static int _spaceavail(struct RingBuf *self);
struct RingBuf *RingBuf_init(unsigned int size)
{
struct RingBuf *self;
if( size<16 )size=16;
if( size>0x10000000u )return 0;
if( size & (size-1) )
{
unsigned int ns;
// is not a power of 2.
size = size<<1;
while(1)
{
ns=size&(size-1);
if(!ns)break;
size=ns;
}
}
self = (struct RingBuf*)vmalloc(sizeof(*self)+size);
memset( self , 0 , sizeof(*self) );
self->buffer = (unsigned char*)(self+1);
self->size = size;
self->inp = 0;
self->outp = 0;
mutex_init( &(self->mtx) );
return self;
}
void RingBuf_uninit(struct RingBuf *self)
{
if(!self)return;
mutex_lock( &(self->mtx) );
mutex_destroy( &(self->mtx) );
memset( self , 0xFE , sizeof(*self) );
vfree(self);
}
int RingBuf_add(struct RingBuf *self,const void *data,int num)
{
int cpy;
if(num<=0)return 0;
mutex_lock( &(self->mtx) );
// check amount to copy
cpy = _spaceavail(self);
if(cpy>num)cpy=num;
// one part or split
if( self->inp+cpy <= self->size )
{
// one chunk
memcpy( self->buffer+self->inp , data , cpy );
}else{
int p1 = (self->size-self->inp);
// wrapped
memcpy( self->buffer+self->inp , data , p1 );
memcpy( self->buffer , ((const unsigned char*)data)+p1 , cpy-p1 );
}
self->inp = (self->inp+cpy) & (self->size-1) ;
mutex_unlock( &(self->mtx) );
return cpy;
}
int RingBuf_get(struct RingBuf *self,void *data,int num)
{
int cpy;
if(num<=0)return 0;
mutex_lock( &(self->mtx) );
// check amount to copy
cpy = _bytesavail(self);
if(cpy>num)cpy=num;
// one part or split
if( self->outp+cpy <= self->size )
{
// one chunk
memcpy( data , self->buffer+self->outp , cpy );
}else{
int p1 = (self->size-self->outp);
// wrapped
memcpy( data , self->buffer+self->outp , p1 );
memcpy( ((unsigned char*)data)+p1 , self->buffer , cpy-p1 );
}
self->outp = (self->outp+cpy) & (self->size-1) ;
mutex_unlock( &(self->mtx) );
return cpy;
}
int RingBuf_get_user(struct RingBuf *self,void __user *data,int num)
{
int cpy;
int ret;
if(num<=0)return 0;
mutex_lock( &(self->mtx) );
// check amount to copy
cpy = _bytesavail(self);
if(cpy>num)cpy=num;
// one part or split
if( self->outp+cpy <= self->size )
{
// one chunk
ret = copy_to_user( data , self->buffer+self->outp , cpy );
}else{
int p1 = (self->size-self->outp);
// wrapped
ret = copy_to_user( data , self->buffer+self->outp , p1 );
if(!ret)
ret = copy_to_user( ((unsigned char*)data)+p1 , self->buffer , cpy-p1 );
}
if(ret)return -1;
self->outp = (self->outp+cpy) & (self->size-1) ;
mutex_unlock( &(self->mtx) );
return cpy;
}
int RingBuf_numBytes(struct RingBuf *self)
{
int result;
mutex_lock( &(self->mtx) );
result = _bytesavail(self);
mutex_unlock( &(self->mtx) );
return result;
}
static int _bytesavail(struct RingBuf *self)
{
return (self->inp-self->outp)&(self->size-1);
}
static int _spaceavail(struct RingBuf *self)
{
return (self->outp-self->inp-1)&(self->size-1);
}