linux - 当从缓冲区直接复制值时,strscp 将永远循环
问题描述
问题
我正在学习 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
它占用CPU 100%。为了让它停止,我必须找到 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
并且使用which 可以正常复制 temp 变量的值。
解决方案
我相信@Tsyvarev 评论了正确的答案。
“至于循环,你声明了 ssize_t len 变量,但从未初始化它。可能,它是 0,所以你的 write 方法总是返回 0,这被用户空间解释为“没有写入任何字节”,用户部分重复一次又一次地写作。”
重构后的代码是:
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;
}
推荐阅读
- angular - 在 XY 轴上显示给定值 - Plotly
- java - 如何配置两个hazelcast缓存(即IMap)一个用于分布式缓存,另一个用于单实例缓存
- javascript - OAuth2 - 如何在没有客户端密码的情况下进行授权?
- sql - 使用 Sql Query 以格式化方式获取用户数据
- javascript - 有没有更简洁的方法来获取我的网址中的最后一个数字?
- jquery - 如果我使用 Ajax 进行 http 请求,curl `-u` 可以转换成什么?
- forms - Typo3 没有为新的 FrontendForms 找到模板
- c - 在c中创建的数组不为空?
- android - Android从网页网址设置自定义字体
- swift - 带有 snapkit 的垂直居中 UIImageView