关于 linux 设备驱动程序第 3 版中 scull_follow 函数的问题
Questions on scull_follow function in linux device drivers 3rd edition
我从未在书中找到 scull_follow 的定义,因此我试图根据 github 存储库 (https://github.com/martinezjavier/ldd3) 来理解它。
这是我试图理解的代码:
struct scull_qset *scull_follow(struct scull_dev *dev, int n) {
struct scull_qset *qs = dev->data;
/* Allocate first qset explicitly if need be */
if (!qs) { // if NULL
qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs == NULL)
return NULL; /* Never mind */
memset(qs, 0, sizeof(struct scull_qset));
}
/* Then follow the list */
while (n--) {
if (!qs->next) {
qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs->next == NULL)
return NULL; /* Never mind */
memset(qs->next, 0, sizeof(struct scull_qset));
}
qs = qs->next;
continue;
}
return qs;
}
这里是结构 scull_qset
:
struct scull_qset {
void **data;
struct scull_qset *next;
};
从概念上讲,我理解 scull_follow
所做的只是跟随列表直到正确的位置,以便您知道从哪里开始 reading/writing。
我主要对这部分代码感到困惑。
/* Allocate first qset explicitly if need be */
if (!qs) { // if NULL
qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs == NULL)
return NULL; /* Never mind */
memset(qs, 0, sizeof(struct scull_qset));
}
假设用户打开此驱动程序并尝试先从中读取而不是写入。那应该意味着它应该进入 if 语句并分配一些内存。那么,为什么要再次检查 qs
是否为 NULL
?它不会因为分配了一些内存而永远不是 NULL 吗?
之后 memset
函数是做什么用的?我知道它将 0 复制到 qs
,但是除了初始化这个内存区域之外还有什么意义呢?是这样吗,当你在你的读取函数中调用 copy_to_user
函数时,它会知道因为它填充了 0,所以没有任何 'value' 被写入它所以你只会得到一个空白输出阅读时,假设你做的第一个操作是阅读?
感谢您回答我的问题。
这个:
qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs == NULL)
return NULL;
是标准 C 编程的好习惯:每当函数失败时,您始终需要检查 return 值。对于任何可能失败的函数都是如此,不仅是 malloc()
和朋友。在这种情况下,kmalloc()
可能无法分配内存,returning NULL
,因此代码正在检查该错误。如果发生这种情况,该函数会通过 return NULL;
安全地中止执行,然后调用者将根据需要进行处理。
这个:
memset(qs, 0, sizeof(struct scull_qset));
是标准内核编程的良好做法:无论何时分配未初始化的内存(如 kmalloc()
所做的),它都可能包含敏感的内核数据。您从不 希望未初始化的数据通过 copy_to_user()
或类似的调用到达用户空间。为了避免这种情况,您需要确保在将其提供给用户空间之前对其进行初始化。使用 memset()
用零填充它是最简单的方法之一。
如果用户程序执行 read
作为 scull 驱动程序的第一个系统调用,它只会读取一堆 0
字节。
我从未在书中找到 scull_follow 的定义,因此我试图根据 github 存储库 (https://github.com/martinezjavier/ldd3) 来理解它。 这是我试图理解的代码:
struct scull_qset *scull_follow(struct scull_dev *dev, int n) {
struct scull_qset *qs = dev->data;
/* Allocate first qset explicitly if need be */
if (!qs) { // if NULL
qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs == NULL)
return NULL; /* Never mind */
memset(qs, 0, sizeof(struct scull_qset));
}
/* Then follow the list */
while (n--) {
if (!qs->next) {
qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs->next == NULL)
return NULL; /* Never mind */
memset(qs->next, 0, sizeof(struct scull_qset));
}
qs = qs->next;
continue;
}
return qs;
}
这里是结构 scull_qset
:
struct scull_qset {
void **data;
struct scull_qset *next;
};
从概念上讲,我理解 scull_follow
所做的只是跟随列表直到正确的位置,以便您知道从哪里开始 reading/writing。
我主要对这部分代码感到困惑。
/* Allocate first qset explicitly if need be */
if (!qs) { // if NULL
qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs == NULL)
return NULL; /* Never mind */
memset(qs, 0, sizeof(struct scull_qset));
}
假设用户打开此驱动程序并尝试先从中读取而不是写入。那应该意味着它应该进入 if 语句并分配一些内存。那么,为什么要再次检查 qs
是否为 NULL
?它不会因为分配了一些内存而永远不是 NULL 吗?
之后 memset
函数是做什么用的?我知道它将 0 复制到 qs
,但是除了初始化这个内存区域之外还有什么意义呢?是这样吗,当你在你的读取函数中调用 copy_to_user
函数时,它会知道因为它填充了 0,所以没有任何 'value' 被写入它所以你只会得到一个空白输出阅读时,假设你做的第一个操作是阅读?
感谢您回答我的问题。
这个:
qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs == NULL)
return NULL;
是标准 C 编程的好习惯:每当函数失败时,您始终需要检查 return 值。对于任何可能失败的函数都是如此,不仅是 malloc()
和朋友。在这种情况下,kmalloc()
可能无法分配内存,returning NULL
,因此代码正在检查该错误。如果发生这种情况,该函数会通过 return NULL;
安全地中止执行,然后调用者将根据需要进行处理。
这个:
memset(qs, 0, sizeof(struct scull_qset));
是标准内核编程的良好做法:无论何时分配未初始化的内存(如 kmalloc()
所做的),它都可能包含敏感的内核数据。您从不 希望未初始化的数据通过 copy_to_user()
或类似的调用到达用户空间。为了避免这种情况,您需要确保在将其提供给用户空间之前对其进行初始化。使用 memset()
用零填充它是最简单的方法之一。
如果用户程序执行 read
作为 scull 驱动程序的第一个系统调用,它只会读取一堆 0
字节。