Системный вызов для обработки и отображения таблицы идентификаторов, имен и их состояний

#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) фактически определяет функцию.