Hay una mejor manera de obtener la instancia de task_struct de un módulo. Siempre intente usar la función de envoltura/rutinas auxiliares porque están diseñadas de tal manera que si el programador del controlador se perdió algo, el núcleo puede encargarse por sí mismo. Por ejemplo:manejo de errores, verificación de condiciones, etc.
/* Use below API and you will get a pointer of (struct task_struct *) */
taskp = get_pid_task(pid, PIDTYPE_PID);
y para obtener el PID de tipo pid_t. necesita usar la siguiente API -
find_get_pid(pid_no);
No necesita usar "rcu_read_lock() " y "rcu_read_unlock() " al llamar a estas API porque "get_pid_task() " llama internamente a rcu_read_lock(),rcu_read_unlock() antes de llamar a "pid_task() " y maneja la concurrencia correctamente. Es por eso que he dicho anteriormente que use este tipo de contenedor siempre.
Fragmento de la función get_pid_task() y find_get_pid() a continuación:-
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);
En un módulo del núcleo, también puede usar la función contenedora de la siguiente manera -
taskp = get_pid_task(find_get_pid(PID),PIDTYPE_PID);
PD:para obtener más información sobre las API, puede consultar kernel/pid.c
Si quieres encontrar el task_struct
de un módulo, find_task_by_vpid(pid_t nr)
etc. no van a funcionar ya que estas funciones no se exportan.
En un módulo, puede usar la siguiente función en su lugar:
pid_task(find_vpid(pid), PIDTYPE_PID);
Nadie mencionó que el pid_task()
función y el puntero (que obtiene de él) debe usarse dentro de la sección crítica de RCU (porque utiliza una estructura de datos protegida por RCU). De lo contrario puede haber ERROR de usar después de liberar .
Hay muchos casos de uso de pid_task()
en las fuentes del kernel de Linux (por ejemplo, en posix_timer_event()
).
Por ejemplo:
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!) */
Obtenga más información sobre la API de RCU en Kernel.org
PD también puede usar las funciones especiales de la API como find_task_by_pid_ns()
y find_task_by_vpid()
bajo el rcu_read_lock()
.
El primero es para buscar a través del espacio de nombres particular:
task = find_task_by_pid_ns(pid_num, &init_pid_ns); /* e.g. init namespace */
El segundo es para buscar a través del espacio de nombres de current
tarea.
¿Qué tiene de malo usar uno de los siguientes?
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);