strap loop forever when 当值直接从缓冲区复制时

strscp loop forever when when the value is copied direcly from the buffer

问题

我正在学习 Linux 内核模块开发并试图理解为什么在复制缓冲区中的值时 strscp 会无限循环。

代码

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/string.h>

#define LEN 13
#define ID "ABCDEF2103a5"
static  char buffer[LEN];

static ssize_t hello_write(struct file *file,
        const char *buf, size_t count,
        loff_t *ppos)
{
    
    ssize_t len;
    
    if (count != LEN)
        return -EINVAL;
    
    // This loops forever when 0 returned!
    strscpy(buffer, buf, LEN);
    
    return len;
}


static const struct file_operations file_ops = {
    .owner  = THIS_MODULE,
    .write  = hello_write,
};

static struct miscdevice misc_dev = {
    MISC_DYNAMIC_MINOR,
    "check",
    &file_ops
};

当值“ABCDEF2103a5”(或任何相同长度的值)通过 echo ABCDEF2103a5 > /dev/check 传递给模块时,它只是连续打印该值。

下面是 dmesg -wH 的输出:

[  +0.000002] ABCDEF2103a5
[  +0.000003] ABCDEF2103a5
[  +0.000003] ABCDEF2103a5
[  +0.000002] ABCDEF2103a5
[  +0.000003] ABCDEF2103a5
[  +0.000002] ABCDEF2103a5
[  +0.000003] ABCDEF2103a5
[  +0.000002] ABCDEF2103a5
[  +0.000003] ABCDEF2103a5
[  +0.000003] ABCDEF2103a5
[  +0.000002] ABCDEF2103a5
[  +0.000008] ABCDEF2103a5 

占CPU100%。为了让它停止,我必须找到 shell 的 PID 并杀死它。

当返回 0 时(len 被赋值为 0 或 return 0),没有打印任何内容并且 bash 挂起。

当返回其他值(0 除外)时,bash: echo: write error:... 会抛出某种形式的错误消息,但不会挂起。

应该返回什么值?我们不能只做return;

工作正常

完整的功能代码,首先将缓冲区复制到一个临时数组,然后将其复制到全局变量。

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/string.h>

#define LEN 13
#define ID "ABCDEF2103a5"
static  char buffer[LEN];

static ssize_t hello_write(struct file *file,
        const char *buf, size_t count,
        loff_t *ppos)
{
    ssize_t len;
    char *msg = kmalloc (count + 1, GFP_KERNEL);

    if (!msg)
        return -ENOMEM;

    if (count != LEN)
        return -EINVAL;

    len = simple_write_to_buffer(msg, count, ppos, buf,
      count);

    if ( strncmp(msg, ID, LEN-1 ) != 0 )
      return -EINVAL;
    
    // Copied from the temporary variable
    // which works fine.
    strscpy(buffer, msg, LEN);

    return len;
}


static const struct file_operations file_ops = {
    .owner  = THIS_MODULE,
    .write  = hello_write,
};

static struct miscdevice misc_dev = {
    MISC_DYNAMIC_MINOR,
    "check",
    &file_ops
};

上面的评论部分未评论。在这里,缓冲区首先被复制到一个临时变量。使用 strscpy 复制临时变量的值,效果很好。

我相信@Tsyvarev 评论了正确答案。

”至于循环,你声明了ssize_t len 变量,但从未初始化它。可能是0,所以你的write方法总是returns 0,这是用户解释的space 因为“没有字节被写入”并且用户部分一次又一次地重复写入。

重构后的代码为:

static ssize_t hello_write(struct file *file,
        const char *buf, size_t count,
        loff_t *ppos)
{

    ssize_t len;
    ssize_t copy_len;
    char *msg = kmalloc(count + 1, GFP_KERNEL);

    if (!msg)
        return -ENOMEM;

    if (count != LEN)
        goto einval;

    len = simple_write_to_buffer(msg, count, ppos,
            buf, count);

    if (len <= 0) {
        kfree(msg);
        return len;
    }

    if (strncmp(msg, ID, LEN-1) != 0)
        goto einval;

    copy_len = strscpy(buffer, strim(msg), LEN);

    if (copy_len < 0) {
        kfree(msg);
        return copy_len;
    }

    return len;

einval:
    kfree(msg);
    return -EINVAL;
}