Linux内核函数返回1而不是EINVAL



我正在尝试添加一个新的系统调用到linux内核:

asmlinkage long sys_set_status(int status) {
if ((status != 0) && (status != 1))
return -EINVAL; //-22
current->status = status;
return 0;
}

在syscall_64。TBL声明:

334 common  set_status      sys_set_status

在syscalls.h中声明:

asmlinkage long sys_set_status(int status);

但是当我测试返回值时:

int set_status(int status) {
long r = syscall(334, status);
return (int)r;
}
int main() {
int res = set_status(-1); //illegal status, should return -EINVAL whish is -22
cout << "return value is: " << res << endl;
return 0;
}

我:

返回值为:-1

long r = syscall(334, status);

From man syscall:

返回值由被调用的系统调用定义。在一般情况下,返回0表示成功。返回值-1表示错误,错误编号保存在errno中。

你是不是直接调用系统调用,你是通过libcsyscall包装器调用它,它执行大约如下:

int syscall(num, ...)
{
/* architecture-specific code to put system call number and args into
appropriate registers */
/* arch-specific code to execute the system call instruction */
int rc = /* arch-specific code to get the result of the system call */ ;
if (rc < 0) { errno = -rc; return -1; }
return 0;
}

如果您不希望发生这种转换,您将不得不自己执行特定于体系结构的部分(在汇编中),然后您将拥有实际的系统调用返回值。

正如受雇俄语所指出的在libcerrno中设置系统调用包装函数,将系统调用的负返回值转换为返回值-1。因此,期望返回值-1,并且应该检查errno的值。

很可能errno将被设置为ENOSYS而不是EINVAL,因为内核系统调用代码是用在大多数64位内核上工作的旧格式编写的。应该更新系统调用的内核代码,以使用SYSCALL_DEFINE1包装器宏(因为系统调用有一个参数),如下所示:

#include <linux/syscalls.h>
SYSCALL_DEFINE1(set_status, int, status)
{
if ((status != 0) && (status != 1))
return -EINVAL; //-22
current->status = status;
return 0;
}

编辑:实际上,如果这是问题,内核应该无法连接由于未定义的符号。但是无论如何您都应该使用新格式(如果可能的话,并且可能不适合2009年之前发布的内核)。

我不确定这个系统调用的意义是什么。当系统调用退出回userland时,任务状态应该设置回0。

相关内容

  • 没有找到相关文章

最新更新