Il existe un meilleur moyen d'obtenir l'instance de task_struct à partir d'un module. Essayez toujours d'utiliser des routines de fonction/d'assistance wrapper car elles sont conçues de telle manière que si le programmeur du pilote a manqué quelque chose, le noyau peut s'en charger lui-même. Par exemple - gestion des erreurs, vérification des conditions, etc.
/* Use below API and you will get a pointer of (struct task_struct *) */
taskp = get_pid_task(pid, PIDTYPE_PID);
et pour obtenir le PID de type pid_t. vous devez utiliser l'API ci-dessous -
find_get_pid(pid_no);
Vous n'avez pas besoin d'utiliser "rcu_read_lock() " et "rcu_read_unlock() " tout en appelant ces API parce que "get_pid_task() " appelle en interne rcu_read_lock(), rcu_read_unlock() avant d'appeler "pid_task() " et gère correctement la simultanéité. C'est pourquoi j'ai dit ci-dessus de toujours utiliser ce type d'emballage.
Extrait de la fonction get_pid_task() et find_get_pid() ci-dessous :-
struct task_struct *get_pid_task(struct pid *pid, enum pid_type type)
{
struct task_struct *result;
rcu_read_lock();
result = pid_task(pid, type);
if (result)
get_task_struct(result);
rcu_read_unlock();
return result;
}
EXPORT_SYMBOL_GPL(get_pid_task);
struct pid *find_get_pid(pid_t nr)
{
struct pid *pid;
rcu_read_lock();
pid = get_pid(find_vpid(nr));
rcu_read_unlock();
return pid;
}
EXPORT_SYMBOL_GPL(find_get_pid);
Dans un module du noyau, vous pouvez également utiliser la fonction wrapper de la manière suivante -
taskp = get_pid_task(find_get_pid(PID),PIDTYPE_PID);
PS :pour plus d'informations sur les API, vous pouvez consulter kernel/pid.c
Si vous voulez trouver le task_struct
d'un module, find_task_by_vpid(pid_t nr)
etc. ne fonctionneront pas car ces fonctions ne sont pas exportées.
Dans un module, vous pouvez utiliser la fonction suivante à la place :
pid_task(find_vpid(pid), PIDTYPE_PID);
Personne n'a mentionné que le pid_task()
fonction et le pointeur (que vous obtenez à partir de celui-ci) doit être utilisé dans la section critique RCU (car il utilise une structure de données protégée par RCU). Sinon il peut y avoir un BUG use-after-free .
Il existe de nombreux cas d'utilisation de pid_task()
dans les sources du noyau Linux (par exemple dans posix_timer_event()
).
Par exemple :
rcu_read_lock();
/* search through the global namespace */
task = pid_task(find_pid_ns(pid_num, &init_pid_ns), PIDTYPE_PID);
if (task)
printk(KERN_INFO "1. pid: %d, state: %#lx\n",
pid_num, task->state); /* valid task dereference */
rcu_read_unlock(); /* after it returns - task pointer becomes invalid! */
if (task)
printk(KERN_INFO "2. pid: %d, state: %#lx\n",
pid_num, task->state); /* may be successful,
* but is buggy (task dereference is INVALID!) */
En savoir plus sur l'API RCU sur Kernel.org
PS vous pouvez également simplement utiliser les fonctions spéciales de l'API comme find_task_by_pid_ns()
et find_task_by_vpid()
sous le rcu_read_lock()
.
Le premier est pour rechercher dans l'espace de noms particulier :
task = find_task_by_pid_ns(pid_num, &init_pid_ns); /* e.g. init namespace */
Le second est pour rechercher dans l'espace de noms de current
tâche.
Qu'y a-t-il de mal à utiliser l'un des éléments suivants ?
extern struct task_struct *find_task_by_vpid(pid_t nr);
extern struct task_struct *find_task_by_pid_ns(pid_t nr,
struct pid_namespace *ns);