#c #linux #linux-kernel #operating-system #system-calls
#c #linux #linux-ядро #операционная система #системные вызовы
Вопрос:
Итак, у меня есть задание, с которым мне трудно разобраться. Назначение состоит в том, чтобы создать системный вызов с именем «mysyscall3», который не принимает никаких входных данных и выдает
./a.out
PID COMM STATE
1 systemd INT
2 kthreadd INT
3 rcu_gp OTHER
4 rcu_par_gp OTHER
6 kworker/0:0H OTHER
7 kworker/u4:0 OTHER
8 mm_percpu_wq OTHER
9 ksoftirqd/0 INT
10 rcu_sched OTHER
11 migration/0 INT
13 cpuhp/0 INT
14 cpuhp/1 INT
15 migration/1 INT
16 ksoftirqd/1 INT
18 kworker/1:0H OTHER
20 kdevtmpfs INT
21 netns OTHER
22 kauditd INT
24 khungtaskd INT
25 oom_reaper INT
26 writeback OTHER
27 kcompactd0 INT
28 ksmd INT
29 khugepaged INT
49 cryptd OTHER
126 kintegrityd OTHER
127 kblockd OTHER
128 blkcg_punt_bio OTHER
129 tpm_dev_wq OTHER
130 md OTHER
131 edac-poller OTHER
132 watchdogd INT
158 kswapd0 INT
161 kthrotld OTHER
162 acpi_thermal_pm OTHER
163 kmpath_rdacd OTHER
164 kaluad OTHER
166 ipv6_addrconf OTHER
226 zswap-shrink OTHER
242 kworker/u5:0 OTHER
456 nvme-wq OTHER
461 nvme-reset-wq OTHER
464 nvme-delete-wq OTHER
484 ena OTHER
507 xfsalloc OTHER
513 xfs_mru_cache OTHER
517 xfs-buf/nvme0n1 OTHER
518 xfs-conv/nvme0n OTHER
519 xfs-cil/nvme0n1 OTHER
520 xfs-reclaim/nvm OTHER
521 xfs-eofblocks/n OTHER
522 xfs-log/nvme0n1 OTHER
523 xfsaild/nvme0n1 INT
524 kworker/0:1H OTHER
609 systemd-journal INT
639 systemd-udevd INT
657 auditd INT
701 dbus-daemon INT
702 irqbalance INT
705 rngd INT
709 chronyd INT
710 polkitd INT
721 sssd INT
746 kworker/1:1H OTHER
756 sssd_be INT
765 sssd_nss INT
775 systemd-logind INT
858 NetworkManager INT
867 tuned INT
1010 systemd-resolve INT
1063 rsyslogd INT
1072 sshd INT
1074 agetty INT
1075 crond INT
1076 agetty INT
1188 kworker/0:2 OTHER
1535 kworker/0:3 OTHER
1546 sshd INT
1550 systemd INT
1554 (sd-pam) INT
1560 sshd INT
1561 bash INT
1691 kworker/u4:1 OTHER
1734 kworker/1:1 OTHER
1746 kworker/1:2 OTHER
1748 a.out RUNNING
86 PIDS 1 RUNNING 43 INT 0 UNINT 0 STOPPED 0 TRACED 42 OTHER
Ниже приведен тестовый код, который будет использоваться для тестирования нашего системного вызова
/* test.c
*
* test syscall3 442
*
* Compile:
* gcc test.c
* Run:
* ./a.out
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#define SYS_mysyscall3 442
/* test.c
*
* gcc test.c # compile
*
* Use dmesg to verify mysyscall3 was received by the kernel, i.e.
*
* dmesg | grep mysyscall3
*
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SYS_mysyscall3 442
int main(int argc, char **argv)
{
int maxp;
long ret;
char *buf;
buf = (char*) malloc(512*2048);
if ( buf == NULL ) {
fprintf(stderr, "Error malloc bufn");
return 1;
}
if (argc != 1) {
printf("mysyscall3 requires no input.n");
return -1;
}
ret = syscall(SYS_mysyscall3, buf);
if ( ret ) { // non-zero return value is an error
fprintf(stderr, "Error: mysyscall3 returned %ld.n", ret);
return 1;
}
printf("%sn", buf);
free(buf);
return 0;
}
И ниже то, что у меня есть до сих пор в моем файле /kernel/sys.c
SYSCALL_DEFINE(mysyscall3) {
struct task_struct *task;
int numPid = 0;
char *buf;
buf = (char *)kmalloc(*buf,GFP_KERNEL);
if (buf == NULL) {
printk(KERN_INFO "mysyscall3 kmallocn");
return -EFAULT;
}
for_each_process(task) {
buf = ("%dt%st%ldn", task->pid,task->comm,task->state);
numPid ;
}
pr_info("%d PIDSn",numPid);
return 0;
}
Итак, я хочу убедиться в нескольких вещах … поскольку в тестовом коде (2-й фрагмент) мой профессор передает параметр buf системному вызову, было бы правильно предположить, что мое фактическое определение должно быть SYSCALL_DEFINE1?
Кроме того, я внес соответствующие изменения в свой файл systables_64, чтобы добавить системный вызов, и все же при новой перестройке и перезапуске ядра, если я запускаю свой тестовый код, на экран ничего не выводится. Должен ли я использовать что-то вроде copy_to_user() , и если да, должен ли я сделать это в for_each_process(3-й кодовый документ). Я хотел бы просто распечатать что-то на своем экране, но вот где я продолжаю застревать, может быть, кто-нибудь может указать мне правильное направление?
Комментарии:
1. Да, вам нужно использовать
SYSCALL_DEFINE1
. Кстати, в вашей реализации системного вызова вы создаете локальную переменнуюbuf
. Как вы ожидаете, что локальная переменная будет распространяться за пределы функции или иным образом выводиться на экран?2. есть ли другой способ перенести его в пользовательское пространство с помощью copy_to_user()?
3.Да, копирование в область пользовательского пространства должно выполняться с
copy_to_user
помощью . Обратите внимание, чтоfor_each_process
это должно использоваться внутри раздела чтения RCU (междуrcu_read_lock()
rcu_read_unlock()
вызовами функций и). Такие операции, какcopy_to_user
, которые включают возможный «спящий режим», не могут быть использованы в разделе чтения RCU, поэтому вам нужно использоватьcopy_to_user
внеfor_each_process
итерации.4. Обратите внимание, что показанный вами код ядра не похож на действительный C. Вам следует обновить свой вопрос.
5. @MarcoBonelli: за исключением строки
buf = ("%dt%st%ldn", task->pid,task->comm,task->state);
, код ядра кажется совершенно корректным. КонструкцияSYSCALL_DEFINE(mysyscall3)
фактически определяет функцию.