ioctl参数(例如0x1268/BLKSSZGET)实际指定在哪里?

Jas*_*n C 7 linux standards kernel ioctl specifications

我正在寻找一个明确的规范描述ioctl 0x1268(BLKSSZGET)的预期参数和行为.

这个数字在许多地方声明(其中没有一个包含确定的参考源),例如linux/fs.h,但我找不到它的规范.

当然,过去某些人确定0x1268会获得设备的物理扇区大小并记录在某处.这些信息来自哪里,我在哪里可以找到它?

编辑:我不是在问BLKSSZGET一般做什么,也不是在问它定义了什么标题.我正在寻找一个明确的,标准化的来源,说明它应该采用什么参数类型以及它应该对任何驱动程序的行为实现它.

具体来说,我问,因为在util-linux 2.23(和2.24)中似乎存在一个错误,blkdiscard其中扇区大小被查询到a uint64_t,但是高32位是未触及的,因为BLKSSZGET 似乎期望一个32位整数,这会导致不正确的扇区大小,不正确的对齐计算以及blkdiscard何时应该成功的失败.所以在我提交补丁之前,我需要绝对确定地确定问题是blkdiscard应该使用32位整数,还是我的内核中的驱动程序实现应该使用64位整数.

编辑2:由于我们是关于这个主题的,所以建议的补丁假定blkdiscard不正确的是:

--- sys-utils/blkdiscard.c-2.23 2013-11-01 18:28:19.270004947 -0400
+++ sys-utils/blkdiscard.c  2013-11-01 18:29:07.334002382 -0400
@@ -71,7 +71,8 @@
 {
    char *path;
    int c, fd, verbose = 0, secure = 0;
-   uint64_t end, blksize, secsize, range[2];
+   uint64_t end, blksize, range[2];
+   uint32_t secsize;
    struct stat sb;

    static const struct option longopts[] = {
@@ -146,8 +147,8 @@
        err(EXIT_FAILURE, _("%s: BLKSSZGET ioctl failed"), path);

    /* align range to the sector size */
-   range[0] = (range[0] + secsize - 1) & ~(secsize - 1);
-   range[1] &= ~(secsize - 1);
+   range[0] = (range[0] + (uint64_t)secsize - 1) & ~((uint64_t)secsize - 1);
+   range[1] &= ~((uint64_t)secsize - 1);

    /* is the range end behind the end of the device ?*/
    end = range[0] + range[1];
Run Code Online (Sandbox Code Playgroud)

适用于例如https://www.kernel.org/pub/linux/utils/util-linux/v2.23/.

Jas*_*n C 7

"这在哪里指定?"的答案 似乎确实是核心来源.

我在这里询问了内核邮件列表中的问题:https://lkml.org/lkml/2013/11/1/620

作为回应,Theodore Ts'o 写道(注意:他错误地在他的列表中发现了sys-utils/blkdiscard.c,但这是无关紧要的):

BLKSSZGET returns an int.  If you look at the sources of util-linux
v2.23, you'll see it passes an int to BLKSSZGET in 

    sys-utils/blkdiscard.c
    lib/blkdev.c

E2fsprogs also expects BLKSSZGET to return an int, and if you look at
the kernel sources, it very clearly returns an int.

The one place it doesn't is in sys-utils/blkdiscard.c, where as you
have noted, it is passing in a uint64 to BLKSSZGET.  This looks like
it's a bug in sys-util/blkdiscard.c.
Run Code Online (Sandbox Code Playgroud)

然后他继续在util-linux上向blkdiscard提交补丁¹:

--- a/sys-utils/blkdiscard.c
+++ b/sys-utils/blkdiscard.c
@@ -70,8 +70,8 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
 int main(int argc, char **argv)
 {
        char *path;
-       int c, fd, verbose = 0, secure = 0;
-       uint64_t end, blksize, secsize, range[2];
+       int c, fd, verbose = 0, secure = 0, secsize;
+       uint64_t end, blksize, range[2];
        struct stat sb;

        static const struct option longopts[] = {
Run Code Online (Sandbox Code Playgroud)

我一直犹豫要不要在我的邮件列表帖子和这个SO问题的原始版本中提到blkdiscard工具,特别是出于这个原因:我知道我的内核的来源是什么,已经很容易修改blkdiscard以同意源代码,并且这最终分散了"这在哪里记录?"的真实问题.

所以,至于具体细节,比我更官方的人也说过BLKSSZGET ioctl采用了int,但关于文档的一般问题仍然存在.然后我跟进了https://lkml.org/lkml/2013/11/3/125并收到了Theodore Ts'o(wiki的可信度)的另一个回复来回答这个问题.他写道:

> There was a bigger question hidden behind the context there that I'm
> still wondering about: Are these ioctl interfaces specified and
> documented somewhere? From what I've seen, and from your response, the
> implication is that the kernel source *is* the specification, and not
> document exists that the kernel is expected to comply with; is this
> the case?

The kernel source is the specification.  Some of these ioctl are
documented as part of the linux man pages, for which the project home
page is here:

     https://www.kernel.org/doc/man-pages/

However, these document existing practice; if there is a discrepancy
between what is in the kernel has implemented and the Linux man pages,
it is the Linux man pages which are buggy and which will be changed.
That is man pages are descriptive, not perscriptive.
Run Code Online (Sandbox Code Playgroud)

我还询问了一般用于公共内核API的"int"的问题,他的回答是存在的,尽管这里的主题是偏离主题的.

答:那么,你有它,最后的答案是:ioctl接口由内核源本身指定; 没有内核遵守的文档.有文档来描述内核的各种ioctl的实现,但如果存在不匹配,则文档中的错误,而不是内核中的错误.

¹考虑到上述所有因素,我想指出,与我的相比,Theodore Ts'o提交的补丁中的一个重要区别是使用"int"而不是"uint32_t" - BLKSSZGET,根据内核源码,确实期望一个参数是平台上的"int"大小,而不是强制的32位值.