我正在使用自定义内核字符设备,它有时会为其ioctl()
返回大的负值(大约数千,比如-2000)。
在用户空间中,我没有从ioctl调用返回这些值。相反,我得到的返回值为-1,errno
设置为内核模块的否定值(+2000)。
就我可以阅读和谷歌而言,__syscall_return()
是应该将负返回值解释为错误的宏。但是,它似乎只寻找介于-1和-125之间的值。所以我没想到要翻译这些大的负值。
这些返回值在哪里被翻译?这是预期的行为吗?
我在Linux 2.6.35.10上使用EGLIBC 2.11.3-4 + deb6u6。
答案 0 :(得分:2)
翻译并移至errno
级libc
。根据{{3}}
libc
和μClibc
都将负数降低至至少-4095
有关libc
的Gnu ioctl
实施内容,请参见http://www.makelinux.net/ldd3/chp-6-sect-1。
答案 1 :(得分:0)
所以,在BRPocock的帮助下,我会在这里报告我的发现。
Linux内核将对(来自unistd.h)的所有系统调用进行错误检查:
#define __syscall_return(type, res) \
do { \
if ((unsigned long)(res) >= (unsigned long)(-125)) { \
errno = -(res); \
res = -1; \
} \
return (type) (res); \
} while (0)
Libc还会对(来自syscall.S)的所有系统调用进行错误检查:
.text
ENTRY (syscall)
PUSHARGS_6 /* Save register contents. */
_DOARGS_6(44) /* Load arguments. */
movl 20(%esp), %eax /* Load syscall number into %eax. */
ENTER_KERNEL /* Do the system call. */
POPARGS_6 /* Restore register contents. */
cmpl $-4095, %eax /* Check %eax for error. */
jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */
ret /* Return to caller. */
PSEUDO_END (syscall)
Glibc给出了4096值的原因(来自sysdep.h):
/* Linux uses a negative return value to indicate syscall errors,
unlike most Unices, which use the condition codes' carry flag.
Since version 2.1 the return value of a system call might be
negative even if the call succeeded. E.g., the `lseek' system call
might return a large offset. Therefore we must not anymore test
for < 0, but test for a real error by making sure the value in %eax
is a real error number. Linus said he will make sure the no syscall
returns a value in -1 .. -4095 as a valid result so we can savely
test with -4095. */
新的内核似乎缺少__ syscall_return,我还没有研究过。