在 Linux 设备驱动程序上进行另一次写入之前清除 buffer/user 数据

Clear buffer/user data before doing another write on a Linux device driver

我正在尝试编写一个简单的 linux 设备驱动程序,将数字放入链表中。我没有使用 copy_from_user,而是使用 strcpy 来复制缓冲区并添加到列表中。这部分工作完美。但是,不知何故,如果我添加的数字比前一个数字少,缓冲区就会填满前一个数字的最后一位数字。

例如,如果我输入:1234,然后输入 11,则 11 会进入缓冲区 1134,其中包含前一次写入的最后一位。

代码如下,是对网络上可以找到的设备驱动程序示例的修改。

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
#include <linux/aio.h>
#include <linux/uaccess.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/device.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zhiyi Huang");
MODULE_DESCRIPTION("A template module");

int major=0;
module_param(major, int, S_IRUGO);
MODULE_PARM_DESC(major, "device major number");

#define MAX_DSIZE   3071
struct my_dev {
    char data[MAX_DSIZE+1];
    size_t size;              
    struct semaphore sem;
    struct cdev cdev;
    struct class *class;
    struct device *device;
} *temp_dev;

struct struct_list {
    int numero;
    struct list_head membro_lista;
};

LIST_HEAD(head) ;

int temp_open (struct inode *inode, struct file *filp) {
    return 0;
}

int temp_release (struct inode *inode, struct file *filp) {
    return 0;
}

char parsed_nums[300];

const char * display(void) {
    struct list_head *iter;
    struct struct_list *objPtr;
    char num[10];
    parsed_nums[0] = '[=12=]';

    list_for_each(iter, &head) {
        objPtr = list_entry(iter, struct struct_list, membro_lista);
        //printk("Elem: %d", objPtr->numero);
        sprintf(num,"%d ",objPtr->numero);
        strcat(parsed_nums, num);
    }
    strcat(parsed_nums, "\n");
    //printk("%s", parsed_nums);
    return parsed_nums;
}

ssize_t temp_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos) {
    //char* parsed_nums = display();
    display();
    printk("%s", parsed_nums);
    int rv=0;

    if (down_interruptible (&temp_dev->sem))
        return -ERESTARTSYS;
    if (*f_pos > MAX_DSIZE) 
        goto wrap_up;     
    if (*f_pos + count > MAX_DSIZE)
        count = MAX_DSIZE - *f_pos;
    if (copy_to_user (buf, temp_dev->data+*f_pos, count)) {
        rv = -EFAULT;
        goto wrap_up;
    }
    up (&temp_dev->sem);
    *f_pos += count;
    return count;
  wrap_up:
    up (&temp_dev->sem);
    return rv;
}

void todo_add_entry(int arg) {
    struct struct_list *fooPtr = (struct struct_list *)kmalloc(sizeof(struct struct_list), GFP_KERNEL);
    fooPtr->numero = arg;

    struct list_head *ptr;
    struct struct_list *entry;
    list_for_each(ptr, &head) {
        entry = list_entry(ptr, struct struct_list, membro_lista);
        if (entry->numero >= fooPtr->numero) {
            list_add_tail(&fooPtr->membro_lista, ptr);
            return;
        }
    }
    list_add_tail(&fooPtr->membro_lista, &head);
}

ssize_t temp_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
    count = 0;
    int count1=count,rv=count;
    int valor;
    printk("AAA: %s", buf);
    kstrtoint(buf, 10, &valor);

    todo_add_entry(valor);
    display();

    if (down_interruptible (&temp_dev->sem))
        return -ERESTARTSYS;
    if (*f_pos > MAX_DSIZE)
        goto wrap_up;
    if (*f_pos + count > MAX_DSIZE)
        count1 = MAX_DSIZE - *f_pos;
    if (strcpy(temp_dev->data, parsed_nums)) {
        goto wrap_up;
    }
    up (&temp_dev->sem);
    *f_pos += count1;
    return count;
  wrap_up:
    up (&temp_dev->sem);
    return rv;
}

struct file_operations temp_fops = {
    .owner =     THIS_MODULE,
    .read =      temp_read,
    .write =     temp_write,
    .open =      temp_open,
    .release =   temp_release,
};

LIST_HEAD(listaDupla) ;

int __init temp_init_module(void){
    int rv;
    dev_t devno = MKDEV(major, 0);

    if(major) {
        rv = register_chrdev_region(devno, 1, "temp");
        if(rv < 0){
            printk(KERN_WARNING "Can't use the major number %d; try atomatic allocation...\n", major);
            rv = alloc_chrdev_region(&devno, 0, 1, "temp");
            major = MAJOR(devno);
        }
    }
    else {
        rv = alloc_chrdev_region(&devno, 0, 1, "temp");
        major = MAJOR(devno);
    }

    if(rv < 0) return rv;
    temp_dev = kmalloc(sizeof(struct my_dev), GFP_KERNEL);
    if(temp_dev == NULL){
        rv = -ENOMEM;
        unregister_chrdev_region(devno, 1);
        return rv;
    }
    memset(temp_dev, 0, sizeof(struct my_dev));
    cdev_init(&temp_dev->cdev, &temp_fops);
    temp_dev->cdev.owner = THIS_MODULE;
    temp_dev->size = MAX_DSIZE;
    sema_init (&temp_dev->sem, 1);
    rv = cdev_add (&temp_dev->cdev, devno, 1);
    if (rv) printk(KERN_WARNING "Error %d adding device temp", rv);
    temp_dev->class = class_create(THIS_MODULE, "temp");
    if(IS_ERR(temp_dev->class)) {
        cdev_del(&temp_dev->cdev);
        unregister_chrdev_region(devno, 1);
        printk(KERN_WARNING "%s: can't create udev class\n", "temp");
        rv = -ENOMEM;
        return rv;
    }
    temp_dev->device = device_create(temp_dev->class, NULL,
                    MKDEV(major, 0), "%s", "temp");
    if(IS_ERR(temp_dev->device)){
        class_destroy(temp_dev->class);
        cdev_del(&temp_dev->cdev);
        unregister_chrdev_region(devno, 1);
        printk(KERN_WARNING "%s: can't create udev device\n", "temp");
        rv = -ENOMEM;
        return rv;
    }

    printk(KERN_WARNING "Hello world from Template Module\n");
    printk(KERN_WARNING "temp device MAJOR is %d, dev addr: %lx\n", major, (unsigned long)temp_dev);

  return 0;
}

void __exit temp_exit_module(void){
    device_destroy(temp_dev->class, MKDEV(major, 0));
    class_destroy(temp_dev->class);
    cdev_del(&temp_dev->cdev); 
    kfree(temp_dev);
    unregister_chrdev_region(MKDEV(major, 0), 1);
    printk(KERN_WARNING "Good bye from Template Module\n");
}

module_init(temp_init_module);
module_exit(temp_exit_module);

这可能是什么原因造成的?有人可以给我建议吗?

实际上,您每次都在同一个缓冲区上写入,因此最后会有垃圾值。

要解决您的问题,您应该在写入后添加一个 '[=10=]'。因此,当您读取缓冲区时,您不会读取垃圾。

如果您的数据可以包含 [=11=],您最好的选择是将缓冲区的大小存储在一个变量中并仅使用该数据量。

您也可以每次都将缓冲区清零,但那样效率很低。