C'è un modo migliore per ottenere l'istanza di task_struct da un modulo. Cerca sempre di usare la funzione wrapper/le routine helper perché sono progettate in modo tale che se il programmatore del driver ha perso qualcosa, il kernel può occuparsene da solo. Ad esempio:gestione degli errori, controlli delle condizioni, ecc.
/* Use below API and you will get a pointer of (struct task_struct *) */
taskp = get_pid_task(pid, PIDTYPE_PID);
e per ottenere il PID di tipo pid_t. è necessario utilizzare l'API sottostante -
find_get_pid(pid_no);
Non è necessario utilizzare "rcu_read_lock() " e "rcu_read_unlock() " durante la chiamata di queste API perché "get_pid_task() " chiama internamente rcu_read_lock(),rcu_read_unlock() prima di chiamare "pid_task() " e gestisce correttamente la concorrenza. Ecco perché ho detto sopra usa sempre questo tipo di wrapper.
Frammento della funzione get_pid_task() e find_get_pid() di seguito :-
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);
In un modulo del kernel, puoi usare la funzione wrapper anche nel modo seguente -
taskp = get_pid_task(find_get_pid(PID),PIDTYPE_PID);
PS:per maggiori informazioni sulle API puoi consultare kernel/pid.c
Se vuoi trovare il file task_struct
da un modulo, find_task_by_vpid(pid_t nr)
ecc. non funzioneranno poiché queste funzioni non vengono esportate.
In un modulo, puoi invece utilizzare la seguente funzione:
pid_task(find_vpid(pid), PIDTYPE_PID);
Nessuno ha detto che il pid_task()
funzione e il puntatore (che ottieni da esso) dovrebbe essere usato all'interno della sezione critica RCU (poiché utilizza una struttura dati protetta da RCU). Altrimenti ci possono essere BUG use-after-free .
Ci sono molti casi di utilizzo di pid_task()
nei sorgenti del kernel Linux (ad esempio in posix_timer_event()
).
Ad esempio:
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!) */
Scopri di più sull'API RCU da Kernel.org
P.S. inoltre puoi semplicemente utilizzare le funzioni API speciali come find_task_by_pid_ns()
e find_task_by_vpid()
sotto il rcu_read_lock()
.
Il primo è per la ricerca attraverso il particolare spazio dei nomi:
task = find_task_by_pid_ns(pid_num, &init_pid_ns); /* e.g. init namespace */
Il secondo è per la ricerca nello spazio dei nomi di current
compito.
Cosa c'è di sbagliato nell'usare uno dei seguenti?
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);