Red de conocimientos turísticos - Información de alquiler - Artículos que le llevarán a comprender la interfaz y la implementación de io_uring

Artículos que le llevarán a comprender la interfaz y la implementación de io_uring

io_uring es una interfaz de E/S asíncrona proporcionada por Linux. io_uring se agregó al kernel de Linux en 2019 y, después de dos años de desarrollo, ahora es muy poderoso. Este artículo presentará la interfaz io_uring basada en Linux 5.12.10.

La implementación de io_uring se encuentra principalmente en fs/io_uring.c.

La implementación de io_uring utiliza solo tres llamadas al sistema: io_uring_setup, io_uring_enter e i_uring_register, que se utilizan para configurar el contexto io_uring, confirmar y obtener finalizaciones, y registrar los buffers habilitados por el usuario del kernel. La interfaz io_uring está disponible mediante las dos primeras llamadas al sistema.

Los usuarios y el kernel envían y completan tareas a través de colas de envío y finalización. Habrá mucha información breve más adelante en el artículo, por lo que aquí se ofrece información introductoria.

El usuario inicializa un nuevo contexto io_uring llamando a io_uring_setup 1. Esta función devuelve un descriptor de archivo que contiene las funciones admitidas por io_uring y los parámetros de compensación para cada estructura de datos en fd. El usuario asigna el fd a la memoria (mmap) en función del desplazamiento para obtener el área de memoria que disfruta el usuario del kernel ****. Esta área de memoria contiene la información de contexto de io_uring: información de la cola de envío (SQ_RING) e información de la cola de finalización (CQ_RING), así como un área dedicada a los elementos de la cola de envío (SQ_RING solo almacena el número de secuencia de SQE en el área de SQE); , mientras CQ_RING Luego se almacenan los datos completos de finalización de la tarea.

En Linux 5, el kernel puede utilizar la región SQE como información de contexto para io_uring. p>

En Linux 5.12, el tamaño SQE es 64B y el tamaño CQE es 16B. Por lo tanto, la misma cantidad de SQE y CQE no requieren la misma cantidad de espacio. Al inicializar io_uring, si el usuario no establece la longitud de CQ en el parámetro, el kernel asigna entradas para SQE y entradas * 2 para CQE.

La sutileza del diseño de io_uring_setup es que el kernel entrega mensajes a través de un área de memoria compartida con el usuario. Una vez creado el contexto, el envío de tareas, la recolección de tareas y otras operaciones se realizarán a través de esta *** área de memoria compartida. En el modo IO_SQPOLL (más sobre esto más adelante), las operaciones que requieren intervención del kernel (como leer y escribir archivos) se pueden realizar sin pasar por el mecanismo de llamadas al sistema de Linux, lo que reduce en gran medida la sobrecarga de llamadas al sistema al cambiar de contexto y vaciar el TLB.

io_uring puede manejar varias solicitudes relacionadas con E/S. Por ejemplo

A continuación se utiliza fsync como ejemplo para presentar las estructuras y funciones que se pueden utilizar para realizar esta operación.

La matriz io_op_def io_op_defs[] define las operaciones admitidas por io_uring y algunos parámetros en io_uring. 3 Por ejemplo, IORING_OP_FSYNC:

Casi todas las operaciones en io_uring tienen una función de preparación y ejecución correspondiente. Por ejemplo, las operaciones fsync corresponden a las funciones io_fsync_prep e io_fsync.

Además de las operaciones sincrónicas (de bloqueo) como fsync, el kernel también admite operaciones llamadas de forma asincrónica (sin bloqueo), como la lectura y escritura de archivos en modo de E/S directa. Para estas operaciones, existe una función preparada asincrónica correspondiente que termina en _async en io_uring. Por ejemplo:

Estas funciones son contenedores io_uring para operaciones de E/S específicas.

El usuario escribe la operación a realizar en el SQ de io_uring. En CQ, los usuarios pueden obtener recompensas por completar tareas. Aquí describimos la codificación de SQE y CQE.

SQE y CQE se definen en include/uapi/linux/io_uring.h 4. SQE es una estructura 64B que contiene toda la información que puede utilizar la operación.

Definición de io_uring_sqe

CQE es una estructura 16B que contiene los resultados de la ejecución de una operación.

Continúe usando fsync como ejemplo. Para realizar una operación fsync en io_uring, debe configurar el código de operación en SQE en IORING_OP_FSYNC, configurar fd en el archivo que se sincronizará y completar fsync_flags. Otras operaciones son similares, configurando el código de operación y escribiendo los parámetros necesarios para la operación en SQE.

En términos generales, los programas que utilizan io_uring utilizarán datos de usuario de 64 bits para identificar de forma única las operaciones 5. "

Dirección de aprendizaje: /course/417774?flowToken=1013300

Necesita materiales de aprendizaje de arquitecto de servidor Linux C/C++ y agregue qun812855908 para obtenerlos (los materiales incluyen C/C++, Linux Tecnología .golang, Nginx, ZeroMQ, MySQL, Redis, fastdfs, MongoDB, ZK, streaming media, CDN, P2P, K8S, Docker, TCP/IP, coprocesamiento, DPDK, ffmpeg, etc.), uso compartido gratuito

io_uring Pass Ring cola e interacción del usuario

Primero presentaremos la interacción del usuario del kernel de io_uring tomando como ejemplo el envío de tareas por parte del usuario.

A continuación, lo presentaremos brevemente. Cómo el kernel obtiene tareas, cómo el kernel completa las tareas y cómo los usuarios recolectan las tareas.

Después de describir la interfaz en modo de usuario de io_uring, Presentaremos cómo se implementa io_uring en el kernel

Al crear un io_uring, hay dos opciones que corresponden a las diferentes formas en que io_uring maneja las tareas:

La configuración de estas. Las opciones afectan la forma en que los usuarios interactúan posteriormente con io_uring:

Cada io_uring está respaldado por un grupo de subprocesos io-wq6 liviano que implementa una implementación de E/S asíncrona en búfer. Para E/S en búfer, el contenido del archivo puede estar en. el caché de la página. También puede ser necesario leerlo desde el disco. Si el contenido del archivo ya está en el caché de la página, se puede leer directamente durante io_uring_enter y recolectarse al regresar al modo de usuario. en la cola de trabajo

Si la opción IORING_SETUP_IOPOLL no se especifica al crear io_uring, la operación io_uring se colocará en io-wq para su ejecución.

La figura anterior cubre toda la llamada. realizado por el usuario a través de io_uring en modo IOPOLL. El SQE enviado por el usuario se procesará a través de una serie de procesos y luego se ejecutará una vez en io_queue_sqe. Después de que todas las operaciones se envíen a la cola del kernel, si el usuario establece el indicador IORING_ENTER_GETEVENTS, io_uring_enter esperará hasta que se complete el número especificado de operaciones y luego regresará al estado de usuario.

Después de eso, Linux programará el hilo del kernel para que se ejecute io-wq. en cualquier momento En este momento, la función io_wq_submit_work continuará realizando la operación especificada por el usuario en modo de bloqueo. Una vez que una operación se ejecuta por completo, su valor de retorno se escribe en CQ.

El usuario puede saber qué operaciones han sido procesadas por el kernel por la posición de la cola de la cola CQ en el contexto io_uring, por lo que no es necesario volver a llamar a i_uring_enter.

Como se puede ver en el gráfico de la llama, cuando IOPOLL está desactivado, el kernel dedicará mucho tiempo a procesar las operaciones de lectura.

Habilite el modo de sondeo de E/S especificando la opción IORING_SETUP_IOPOLL al crear io_uring. En general, los archivos abiertos en modo O_DIRECT admiten el modo de sondeo para operaciones de lectura/escritura.

En modo de sondeo, io_uring_enter solo envía operaciones a la cola de lectura/escritura de archivos del kernel. Luego, el usuario debe llamar a io_uring_enter varias veces para sondear si la operación se completó.

En modo de sondeo, no se utiliza io-wq. Al enviar una tarea, io_read llamará directamente a la interfaz Direct I/O del kernel y enviará la tarea a la cola de dispositivos.

Si el usuario configura el indicador IORING_ENTER_GETEVENTS, io_uring_enter sondeará la interfaz del kernel a través de io_iopoll_check para determinar si la tarea se completó antes de regresar al modo de usuario.

Como se puede ver en el gráfico de llamas, io_uring_enter solo dedica una pequeña parte del tiempo a la parte de envío. La mayor parte del tiempo se dedica a sondear si las operaciones de E/S están completas.

En un entorno de producción real, a menudo necesitamos escribir en el archivo n veces y luego usar fsync para descartar el disco. Cuando se utiliza io_uring, las tareas en SQ no necesariamente se ejecutan de forma secuencial. Configurar la opción IO_SQE_LINK en una operación establecerá una relación secuencial entre las tareas. La primera tarea después de IO_SQE_LINK debe ejecutarse una vez completada la tarea actual. Cada operación se convertirá en un objeto io_kiocb después de ser procesada por io_submit_sqe. io_submit_sqe 8 maneja SQE que contienen IO_SQE_LINK de la siguiente manera:

Los registros IO_SQE_LINK consecutivos en el SQ parecen procesarse secuencialmente. Todas las tareas se envían antes del final de io_submit_sqes. Por lo tanto, si las tareas tienen una relación secuencial, deben enviarse en lotes en la misma llamada al sistema io_submitting_enter.

Otras opciones para controlar las dependencias de tareas de io_uring incluyen IOSQE_IO_DRAIN e IOSQE_IO_HARDLINK, que no se analizan aquí.