Linux的内核模块写入卡死,dmesg循环打印 Write!

84 阅读3分钟

我写了一个Linux的内核模块,当我该模块作为device时,当要去写入函数时,dmesg循环打印"Write!,为什么呢?代码如下:

#include <linux/types.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>   /* copy_to_user */


MODULE_LICENSE("GPL");
MODULE_AUTHOR("author");
MODULE_DESCRIPTION("module demo");

//-----------------------------------------------------------------------------
// Parameters
//-----------------------------------------------------------------------------

#define MODULE_NAME "fakemodule"
#define CLASS_NAME "modcls"
#define NUM_MINORS 1

#define SUCCESS 0

static dev_t devno;

typedef struct {
  struct cdev cdv;
  struct class *cls;
  struct device *dev;
} fakemodule_t;

fakemodule_t mymod;

//-----------------------------------------------------------------------------
// File Operations
//-----------------------------------------------------------------------------

int fakemodule_open(struct inode *inode, struct file *filp)
{
  printk("Opened!\n");
  return SUCCESS;
}

int fakemodule_release(struct inode *inode, struct file *filp)
{
  printk("Closed!\n");
  return SUCCESS;
}

ssize_t fakemodule_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
  printk("Write!\n");
  return 0;
}

ssize_t fakemodule_read(struct file *filp, char * buf, size_t count, loff_t *f_pos)
{
  printk("Read!\n");
  return 0;
}

struct file_operations fakemodule_fops = {
  owner:    THIS_MODULE,
  read:     fakemodule_read,
  write:    fakemodule_write,
  open:     fakemodule_open,
  release:  fakemodule_release
};

//-----------------------------------------------------------------------------
// Module Init/Exit
//-----------------------------------------------------------------------------

static int __init fakemodule_init(void)
{
  int retval = SUCCESS;

  //Request a set of character device numbers
  printk("Registering Driver\n");
  if ((retval = alloc_chrdev_region(&devno, 0, NUM_MINORS, MODULE_NAME)) != 0)
  {
    printk("Failed to create chrdev region");
    goto init_fail;
  }
  mymod.cls = class_create(THIS_MODULE, CLASS_NAME);
  if (IS_ERR(mymod.cls))
  {
    retval = PTR_ERR(mymod.cls);
    printk("Failed to create module class\n");
    goto probe_class_fail;
  }

  if (IS_ERR(mymod.dev))
  {
    retval = PTR_ERR(mymod.dev);
    printk("Failed to create module class device\n");
    goto probe_device_class_fail;
  }

  //Initialize each of the possible character devices
  cdev_init(&mymod.cdv, &fakemodule_fops);
  if ((retval = cdev_add(&mymod.cdv, devno, 1)) != 0){
    printk("Error %d while trying to add cdev\n", retval);
    goto probe_cdev_init_fail;
  }

  printk("Driver Initialized!\n");
  return SUCCESS;

//Handle Fail
probe_cdev_init_fail:
  device_destroy(mymod.cls, MKDEV(MAJOR(devno), 0));
probe_device_class_fail:
  class_destroy(mymod.cls);
probe_class_fail:
  unregister_chrdev_region(devno, 1);
init_fail:
  return retval;
}

static void __exit fakemodule_exit(void)
{
  //int major = 0;

  printk("Cleanup Module\n");

  printk("Unregistering Character Driver\n");
  cdev_del(&mymod.cdv);
  printk("Give back all the numbers we requested\n");
  unregister_chrdev_region(devno, NUM_MINORS);
  printk("Remove the class driver");
  device_destroy(mymod.cls, MKDEV(MAJOR(devno), 0));
  printk("Release the class");
  class_unregister(mymod.cls);
  class_destroy(mymod.cls);
  printk("Finished Cleanup Module, Exiting\n");
  return;
}

module_init(fakemodule_init);
module_exit(fakemodule_exit);

根据您给出的代码,您的内核模块实现了一组字符设备操作。其中,在fakemodule_write函数中,每次有写入操作发生时,都会通过printk输出"Write!"到内核日志。

如果您在dmesg看到连续打印的"Write!",那么有以下可能的原因:

  1. 高频率的写请求:可能有一个或多个进程/应用正在频繁地写入到您的字符设备。

  2. 错误的设备路径:有些程序可能不小心或错误地反复写入到您的设备路径。

  3. 返回值问题:在fakemodule_write函数中,您返回了0,表示一次写入操作没有实际写入任何数据。这可能会导致调用write的用户空间程序认为没有数据被写入,因此它可能会不断重试。您应该返回count(实际希望写入的字节数)或在出错时返回一个负数的错误码。

解决建议:

  1. 检查写请求的来源:您可以通过lsof或其他工具检查哪些进程正在使用您的字符设备。这可以帮助您确定是否有进程频繁地写入。

  2. 返回适当的值:在fakemodule_write函数中返回count以表示已成功处理的字节数。这样用户空间的程序就知道它的写操作已经完成。

ssize_t fakemodule_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
  printk("Write!\n");
  return count; // indicate all bytes are "handled"
}
  1. 添加更多的日志输出:您可以在fakemodule_write函数中添加更多的日志,以帮助您更好地理解写请求的内容和来源。

最后,请确保您的模块正确处理并防止潜在的资源竞争或多线程问题,这些问题也可能导致异常的行为。