c++ - cpuinfo - ¿Es seguro analizar un archivo/proc/?
comando proc cpuinfo linux (7)
/ proc es un sistema de archivos virtual: de hecho, solo ofrece una vista conveniente de las partes internas del kernel. Definitivamente es seguro leerlo (es por eso que está aquí) pero es arriesgado a largo plazo, ya que el interno de estos archivos virtuales puede evolucionar con una versión más nueva de kernel.
EDITAR
Más información disponible en documentación de proceso en Linux kernel doc , capítulo 1.4 Networking. No puedo encontrar si la información sobre cómo evoluciona la información a lo largo del tiempo. Pensé que estaba congelado en abierto, pero no puedo tener una respuesta definitiva.
EDIT2
De acuerdo con Sco doc (no Linux, pero estoy bastante seguro de que todos los sabores de * nix se comportan así)
Aunque el estado del proceso y, en consecuencia, el contenido de los archivos / proc puede cambiar de instante a instante, se garantiza que una sola lectura (2) de un archivo / proc devolverá una representación de estado "sana", es decir, la lectura será una instantánea atómica del estado del proceso. Ninguna garantía de este tipo se aplica a sucesivas lecturas aplicadas a un archivo / proc para un proceso en ejecución. Además, la atomicidad no se garantiza específicamente para ninguna E / S aplicada al archivo como (espacio de direcciones); el contenido del espacio de direcciones de cualquier proceso puede ser modificado simultáneamente por un LWP de ese proceso o cualquier otro proceso en el sistema.
Quiero analizar /proc/net/tcp/
, pero ¿es seguro?
¿Cómo debo abrir y leer archivos de /proc/
y no tener miedo de que algún otro proceso (o el sistema operativo en sí) lo cambie al mismo tiempo?
A falta de errores desconocidos, no existen condiciones de carrera en /proc
que lleven a la lectura de datos dañados o una mezcla de datos antiguos y nuevos. En este sentido, es seguro. Sin embargo, aún existe la condición de que muchos de los datos que lees de /proc
potencialmente desactualizados tan pronto como se generen, e incluso más cuando lo hayas leído / procesado. Por ejemplo, los procesos pueden morir en cualquier momento y a un nuevo proceso se le puede asignar el mismo pid; los únicos identificadores de proceso que puedes usar sin condiciones de carrera son tus propios procesos secundarios ". Lo mismo ocurre con la información de red (puertos abiertos, etc.) y la mayoría de la información en /proc
. Considero que es una práctica mala y peligrosa confiar en que cualquier información en /proc
sea precisa, excepto datos sobre su propio proceso y potencialmente sus procesos secundarios. Por supuesto, puede ser útil presentar otra información de /proc
al usuario / administrador para información / registro / etc. propósitos.
Aunque los archivos en /proc
aparecen como archivos regulares en el espacio de usuario, no son realmente archivos sino entidades que admiten las operaciones de archivo estándar desde el espacio de usuario ( open
, read
, close
). Tenga en cuenta que esto es bastante diferente de tener un archivo ordinario en el disco que está siendo modificado por el kernel.
Todo lo que hace el kernel es imprimir su estado interno en su propia memoria usando una función tipo sprintf
, y esa memoria se copia en el espacio de usuario cada vez que emite una llamada al sistema de read(2)
.
El núcleo maneja estas llamadas de una manera completamente diferente a la de los archivos normales, lo que podría significar que la instantánea completa de los datos que leerá estará lista en el momento en que la open(2)
, mientras que el núcleo se asegura de que las llamadas concurrentes sean consistente y atómico. No lo he leído en ninguna parte, pero realmente no tiene sentido ser de otra manera.
Mi consejo es echar un vistazo a la implementación de un archivo de proceso en su particular sabor Unix. Esto es realmente un problema de implementación (como es el formato y el contenido de la salida) que no se rige por un estándar.
El ejemplo más simple sería la implementación del archivo de proceso de uptime
de uptime
en Linux. Observe cómo se produce todo el buffer en la función de devolución de llamada proporcionada a single_open
.
Cuando lee desde un archivo / proc, el kernel llama a una función que ha sido registrada previamente para ser la función "leer" para ese archivo de proceso. Consulte la función __proc_file_read
en fs / proc / generic.c.
Por lo tanto, la seguridad de la lectura del proceso es tan segura como la función que el kernel llama para satisfacer la solicitud de lectura. Si esa función bloquea correctamente todos los datos que toca y regresa a usted en un búfer, entonces es completamente seguro leer usando esa función. Dado que los archivos de proc como el utilizado para satisfacer las solicitudes de lectura a / proc / net / tcp han estado disponibles por un tiempo y han sido sometidos a una revisión escrupulosa, son tan seguros como usted podría pedirlos. De hecho, muchas utilidades comunes de Linux dependen de la lectura del sistema de archivos proc y del formato de la salida de una manera diferente. (Fuera de mi cabeza, creo que ''ps'' y ''netstat'' hacen esto).
Como siempre, no tienes que creer en mi palabra; puedes mirar la fuente para calmar tus miedos. La siguiente documentación de proc_net_tcp.txt le dice dónde viven las funciones de "lectura" para / proc / net / tcp, para que pueda ver el código real que se ejecuta cuando lee de ese archivo de proceso y verificar por sí mismo que no hay riesgos de bloqueo.
Este documento describe las interfaces / proc / net / tcp y / proc / net / tcp6.
Tenga en cuenta que estas interfaces están en desuso en favor de tcp_diag. Estas interfaces / proc proporcionan información sobre las conexiones TCP actualmente activas, y se implementan mediante tcp4_seq_show () en net / ipv4 / tcp_ipv4.c y tcp6_seq_show () en net / ipv6 / tcp_ipv6.c, respectivamente.
La API procfs en el kernel de Linux proporciona una interfaz para garantizar que las lecturas devuelvan datos consistentes. Lea los comentarios en __proc_file_read
. El ítem 1) en el gran bloque de comentarios explica esta interfaz.
Una vez dicho esto, por supuesto depende de la implementación de un archivo de proceso específico utilizar esta interfaz correctamente para garantizar que los datos devueltos sean consistentes. Por lo tanto, para responder a su pregunta: no, el kernel no garantiza la coherencia de los archivos de proceso durante una lectura, pero proporciona los medios para la implementación de esos archivos para proporcionar consistencia.
Tengo la fuente para Linux 2.6.27.8 a mano ya que estoy desarrollando controladores en este momento en un objetivo de ARM incrustado.
El archivo ... linux-2.6.27.8-lpc32xx/net/ipv4/raw.c
en la línea 934 contiene, por ejemplo
seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d/n",
i, src, srcp, dest, destp, sp->sk_state,
atomic_read(&sp->sk_wmem_alloc),
atomic_read(&sp->sk_rmem_alloc),
0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
que salidas
[wally@zenetfedora ~]$ cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 15160 1 f552de00 299
1: 00000000:C775 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 13237 1 f552ca00 299
...
en la función raw_sock_seq_show()
que es parte de una jerarquía de funciones de manejo de procfs . El texto no se genera hasta que se realiza una solicitud de read()
archivo /proc/net/tcp
, un mecanismo razonable ya que las lecturas de procfs son mucho menos comunes que la actualización de la información.
Algunos controladores (como el mío) implementan la función proc_read con un solo sprintf()
. La complicación adicional en la implementación de los controladores del núcleo es manejar una salida potencialmente muy larga que puede no ajustarse en el buffer intermedio del kernel-espacio durante una sola lectura.
Probé eso con un programa que usa un buffer de lectura de 64K pero resulta en un buffer de espacio de kernel de 3072 bytes en mi sistema para que proc_read devuelva datos. Se necesitan varias llamadas con indicadores avanzados para obtener más de lo que se devuelve el texto. No sé cuál es la forma correcta de hacer que los datos devueltos sean consistentes cuando se necesita más de una E / S. Ciertamente, cada entrada en /proc/net/tcp
es auto consistente. Existe cierta probabilidad de que las líneas una al lado de la otra sean una instantánea en diferentes momentos.
En general, no. (Entonces, la mayoría de las respuestas aquí están equivocadas.) Puede ser seguro, dependiendo de qué propiedad desee. Pero es fácil terminar con errores en tu código si asumes demasiado sobre la consistencia de un archivo en /proc
. Por ejemplo, vea este error que proviene de suponer que /proc/mounts
fue una instantánea consistente .
Por ejemplo:
/proc/uptime
es totalmente atómico , como alguien mencionó en otra respuesta, pero solo desde Linux 2.6.30 , que tiene menos de dos años. Así que incluso este archivo pequeño y trivial estuvo sujeto a una condición de carrera hasta entonces, y todavía está en la mayoría de los núcleos empresariales. Consultefs/proc/uptime.c
para la fuente actual o la confirmación que la hizo atómica . En un kernel anterior a la 2.6.30, puedeopen
el archivo,read
un poco, luego, si vuelve y vuelve aread
, la pieza que obtenga será inconsistente con la primera. (Acabo de demostrar esto, pruébalo tú mismo por diversión)./proc/mounts
es atómico dentro de una única llamada al sistema deread
. Por lo tanto, siread
todo el archivo de una sola vez, obtendrá una única instantánea consistente de los puntos de montaje en el sistema. Sin embargo, si utiliza varias llamadas al sistema deread
, y si el archivo es grande, esto es exactamente lo que sucederá si usa bibliotecas de E / S normales y no presta especial atención a este problema, estará sujeto a una condición de carrera. No solo no obtendrá una instantánea consistente, sino que los puntos de montaje que estaban presentes antes de comenzar y que nunca dejaron de estar presentes podrían desaparecer en lo que ve. Para ver que es atómico para unaread()
, mirem_start()
enfs/namespace.c
y vea cómo agarra un semáforo que protege la lista de puntos de montaje, que guarda hastam_stop()
, que se llama cuando seread()
está hecho. Para ver qué puede salir mal, vea este error del año pasado (el mismo que he vinculado anteriormente) en otro software de alta calidad que lee/proc/mounts
alegremente./proc/net/tcp
, que es el que realmente está preguntando, es incluso menos consistente que eso. Es atómico solo dentro de cada fila de la mesa . Para ver esto, miralistening_get_next()
ennet/ipv4/tcp_ipv4.c
yestablished_get_next()
justo debajo en el mismo archivo, y mira los bloqueos que sacan en cada entrada por turno. No tengo el código de reproducción a mano para demostrar la falta de coherencia de una fila a otra, pero no hay bloqueos allí (ni nada) que lo haga coherente. Lo cual tiene sentido si lo piensas, las redes son a menudo una parte muy ocupada del sistema, por lo que no vale la pena sobrecargar una vista consistente en esta herramienta de diagnóstico.
La otra pieza que mantiene /proc/net/tcp
atomic dentro de cada fila es el almacenamiento en memoria en seq_read()
, que puede leer en fs/seq_file.c
. Esto garantiza que una vez que read()
parte de una fila, el texto de toda la fila se mantenga en un búfer para que la próxima read()
obtenga el resto de esa fila antes de comenzar una nueva. El mismo mecanismo se usa en /proc/mounts
para mantener cada fila atómica incluso si realiza múltiples llamadas de read()
, y también es el mecanismo que /proc/uptime
en núcleos más nuevos usa para mantenerse atómico. Ese mecanismo no almacena en búfer todo el archivo, porque el kernel es prudente con el uso de la memoria.
La mayoría de los archivos en /proc
serán al menos tan consistentes como /proc/net/tcp
, con cada fila una imagen consistente de una entrada con la información que proporcionan, porque la mayoría usa la misma abstracción seq_file
. Sin embargo, como ilustra el ejemplo de /proc/uptime
, algunos archivos todavía se estaban migrando para usar seq_file
tan recientemente como 2009; Apuesto a que todavía hay algunos que usan mecanismos más antiguos y que ni siquiera tienen ese nivel de atomicidad. Estas advertencias rara vez se documentan. Para un archivo dado, su única garantía es leer la fuente.
En el caso de /proc/net/tcp
, puede leerlo y analizar cada línea sin temor. Pero si tratas de sacar conclusiones de múltiples líneas a la vez, ten cuidado, otros procesos y el kernel lo están cambiando mientras lo lees, y probablemente estés creando un error.