* call foo, go to sys_call_table[__NR_foo]. */
printk("Spying on UID:%d\n", uid);
/* Get the system call for getuid */
getuid_call = sys_call_table[__NR_getuid];
return 0;
}
/* Cleanup - unregister the appropriate file from /proc */
void cleanup_module() {
/* Return the system call back to normal */
if (sys_call_table[__NR_open] != our_sys_open) {
printk("Somebody else also played with the ");
printk("open system call\n");
printk("The system may be left in ");
printk("an unstable state.\n");
}
sys_call_table[__NR_open] = original_call;
}
Отложенные процессы
Что Вы делаете, когда кто-то просит Вас о чем-то, что Вы не можете сделать сразу же? Если вы человек, и вы обеспокоены, единственное, что Вы можете сказать: «Не сейчас, я занят.». Но если вы модуль, Вы имеете другую возможность. Вы можете поместить процесс в спячку, чтобы он бездействовал, пока Вы не сможете обслужить его. В конце концов, процессы помещаются в спячку и пробуждаются ядром постоянно.
Этот модуль является примером этого подхода. Файл (названный /proc/sleep) может быть открыт только одним процессом сразу. Если файл уже открыт, модуль называет module_interruptible_sleep_on[7]. Эта функция изменяет состояние задачи (задача является структурой данных в ядре, которая хранит информацию относительно процесса и системного вызова) в состояние TASK_INTERRUPTIBLE, что означает, что задача не будет выполняться пока не будет пробуждена так или иначе, и добавляет процесс к WaitQ, очереди задач ждущих, чтобы обратиться к файлу. Затем функция обращается к планировщику за контекстным переключателем другого процесса, который может использовать CPU, то есть управление передается другому процессу.
Когда процесс закончит работу с файлом, тот закрывается, и вызывается module_close. Эта функция пробуждает все процессы в очереди (нет никакого механизма, чтобы пробудить только одни из них). Управление возвращается и процесс, который только закрыл файл, может продолжать выполняться. Планировщик решает, что тот процесс поработал достаточно и передает управление другому процессу. В конечном счете, один из процессов, который был в очереди, получит управление. Он продолжит выполнение с той точки, в которой был вызван module_interruptible_sleep_on[8]. Он может установить глобальную переменную, чтобы сообщить всем другим процессам, что файл является все еще открытым. Когда другие процессы получат часть времени CPU, они увидят глобальную переменную и продолжат спячку.
Чтобы сделать нашу жизнь более интересной, module_close не имеет монополии на пробуждение процессов которые ждут, чтобы обратиться к файлу. Сигнал Ctrl-C (SIGINT) может также пробуждать процесс[9]. В таком случае, мы хотим возвратить -EINTR немедленно. Это важно, так как пользователи могут, например, уничтожить процесс прежде, чем он получит доступ к файлу.
Имеется еще одна хитрость. Некоторые процессы не хотят спать: они хотят или получать то, что они хотят, немедленно или сообщить, что действие не может быть выполнено. Такие процессы используют флажок O_NONBLOCK при открытии файла. Ядро отвечает, возвращая код ошибки -EAGAIN из операций, которые иначе блокировали бы, типа открытия файла в этом примере. Программа cat_noblock, доступная в исходном каталоге для этой главы, может использоваться, чтобы открыть файл с флагом O_NONBLOCK.
/* sleep.c - create a /proc file, and if several
* processes try to open it at the same time, put all
* but one to sleep */
/* Copyright (C) 1998-99 by Ori Pomerantz */
/* The necessary header files */
/* Standard in kernel modules */
#include
#include
/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include
#endif
/* Necessary because we use proc fs */
#include
/* For putting processes to sleep and waking them up */
#include
#include
/* In 2.2.3 /usr/include/linux/version.h includes a