C Linux内核中的链表冻结机器
我编写了一个内核模块,需要将消息推送到用户空间。其思想是,内核模块缓冲消息并向用户空间程序发送信号,然后用户空间程序通过netlink套接字请求消息来获取消息。我的问题是,在缓冲90条消息后,机器会锁定,我需要重新启动。我不知道我做错了什么,我在内核模块的其他地方成功地使用了链表C Linux内核中的链表冻结机器,c,linux,linux-kernel,linked-list,C,Linux,Linux Kernel,Linked List,我编写了一个内核模块,需要将消息推送到用户空间。其思想是,内核模块缓冲消息并向用户空间程序发送信号,然后用户空间程序通过netlink套接字请求消息来获取消息。我的问题是,在缓冲90条消息后,机器会锁定,我需要重新启动。我不知道我做错了什么,我在内核模块的其他地方成功地使用了链表 // // A message from the kernel space to user space. // typedef struct CoreLinkMessage { unsigned int id
//
// A message from the kernel space to user space.
//
typedef struct CoreLinkMessage
{
unsigned int id;
char* data;
unsigned int length;
struct list_head list; // kernel's list structure
} CoreLinkMessage;
此函数初始化列表和信号量:
// Constructor
void
ctsRtNetlinkSystem_init( void )
{
sema_init(&cmd_sem_, 1);
INIT_LIST_HEAD(&cmd_list_.list);
}
这一定是导致问题的功能。它只是将一个项目推到链表的尾部。如果我注释掉向链表中添加的项目,并且只调用一个信号,那么程序将无限期运行,因此我认为问题不在于信号
//
// Allows the kernel module to buffer messages until requested by
// the user space
//
void
ctsRtNetlinkSystem_addMessage(char* data, unsigned int length)
{
CoreLinkMessage* msg;
int sem_ret;
BOOL doSignal = FALSE;
//
// LOCK the semaphore
//
sem_ret = down_interruptible(&cmd_sem_);
if ( !sem_ret )
{
msg = (CoreLinkMessage*)kmalloc(sizeof(CoreLinkMessage), GFP_KERNEL );
if ( msg == NULL )
{
PRINTF(CTSMSG_INFO
"ctsRtNetlinkSystem_addMessage failed to allocate memory! \n" );
goto unlock;
}
memset( msg, 0, sizeof(CoreLinkMessage) );
msg->data = (char*)kmalloc( length, GFP_KERNEL );
if ( msg->data == NULL )
{
kfree( msg );
PRINTF(CTSMSG_INFO
"ctsRtNetlinkSystem_addMessage failed to allocate data memory!\n" );
goto unlock;
}
memcpy( msg->data, data, length );
msg->length = length;
lastMessageId_ += 1;
msg->id = lastMessageId_;
list_add_tail(&(msg->list), &cmd_list_.list);
doSignal = TRUE;
unlock:
up( &cmd_sem_ );
if ( doSignal )
sendMessageSignal( msg->id );
}
else
{
PRINTF(CTSMSG_INFO
"CtsRtNetlinkSystem_addMessage -- failed to get semaphore\n" );
}
}
//
// Signal the user space that a message is waiting. Pass along the message
// id
//
static BOOL
sendMessageSignal( unsigned int id )
{
int ret;
struct siginfo info;
struct task_struct *t;
memset(&info, 0, sizeof(struct siginfo));
info.si_signo = SIGNAL_MESSAGE;
info.si_code = SI_QUEUE; // this is bit of a trickery:
// SI_QUEUE is normally used by sigqueue
// from user space,
// and kernel space should use SI_KERNEL.
// But if SI_KERNEL is used the real_time data
// is not delivered to the user space signal
// handler function.
// tell the user space application the index of the message
// real time signals may have 32 bits of data.
info.si_int = id;
rcu_read_lock();
//find the task_struct associated with this pid
t = // find_task_by_pid_type( PIDTYPE_PID, registeredPid_ );
// find_task_by_pid_type_ns(PIDTYPE_PID, nr, &init_pid_ns);
pid_task(find_vpid(registeredPid_), PIDTYPE_PID);
if(t == NULL)
{
PRINTF(CTSMSG_INFO
"CtsRtNetlinkSystem::sendMessageSignal -- no such pid\n");
rcu_read_unlock();
registeredPid_ = 0;
return FALSE;
}
rcu_read_unlock();
//send the signal
ret = send_sig_info(SIGNAL_MESSAGE, &info, t);
if (ret < 0)
{
PRINTF(CTSMSG_INFO
"CtsRtNetlinkSystem::sendMessageSignal -- \n"
"\t error sending signal %d \n", ret );
return FALSE;
}
return TRUE;
}
提前感谢您的帮助。分配的内存不足 请确保为字符串长度+1分配足够的内存以存储其终止符。
发送时,可能需要
长度+1
// ctsRtNetlink_send( &msg[0], strlen(msg) );
ctsRtNetlink_send( &msg[0], strlen(msg) + 1); // +1 for \0
虽然您的代码流在这个问题上不是很清楚,但我觉得添加列表可能不是问题所在。您必须在其他地方处理列表,您必须从列表中删除消息,等等。我怀疑列表添加和删除之间存在某种死锁情况。此外,请检查将消息复制到用户空间并从列表中删除并释放消息的位置。我想,您并不是像上面的评论员所建议的那样,直接从用户空间引用您的mesg 而且
memset( msg, 0, sizeof(CoreLinkMessage) );
if ( msg == NULL )
{
这两行必须颠倒顺序,否则,如果alloc失败,你的系统就注定要失败 使用GFP_原子代替kmalloc的GFP_内核解决了这个问题。到目前为止运行了三天,没有崩溃。我怀疑一个人不能在由hrtimer触发的线程中睡觉
msg = (CoreLinkMessage*)kmalloc(sizeof(CoreLinkMessage), GFP_ATOMIC );
谢谢大家的见解 诺诺诺。用户空间和内核空间神圣地分开。一个不是简单地在两者之间传递信息。此外,您似乎忽略了
memcpy
s和\u send
s中的空终止符('\0'
)。永远记住:strlen(str)+1
。现在没有任何东西被推入内核;问题完全在内核内部。使用GFP_原子而不是GFP_内核似乎解决了这个问题。可能是因为我是从hrtimer回调调用的,kmalloc不能被允许睡眠?其他一些未关闭的例程,如list\u add\u tail()
,可能是错误的@joe关于memset()
的看法是正确的。如果看不到CoreLinkMessage
结构、示例输入和其他附近的例程,这个问题的解决方案很难识别。list_add_tail()是Linux内核的一部分。我添加了所有正在运行的内容。@user761576感谢列表\u add\u tail()。也许把“kernel”标签改为“linux内核”,因为这篇文章是专门针对那个内核的,而不是一般的内核。这是倒退。我会修好的。
msg = (CoreLinkMessage*)kmalloc(sizeof(CoreLinkMessage), GFP_ATOMIC );