Ecriture de programmes pour faire face aux erreurs d'E / S provoquant des écritures perdues sous Linux


Answers

Puisque l'application write () aura déjà retourné sans erreur, il ne semble pas possible de signaler une erreur à l'application.

Je ne suis pas d'accord. write peut retourner sans erreur si l'écriture est simplement mise en file d'attente, mais l'erreur sera signalée sur l'opération suivante qui nécessitera l'écriture réelle sur le disque, à la prochaine fsync , éventuellement sur une écriture suivante si le système décide de vider le cache et au moins sur le dernier fichier à proximité.

C'est la raison pour laquelle il est essentiel pour l'application de tester la valeur de retour de close pour détecter d'éventuelles erreurs d'écriture.

Si vous avez vraiment besoin d'être capable de faire un traitement d'erreur intelligent, vous devez supposer que tout ce qui a été écrit depuis la dernière fsync réussie a échoué et que tout au moins quelque chose a échoué.

Question

TL; DR: Si le noyau Linux perd une écriture d'E / S tamponnée , l'application peut-elle le trouver?

Je sais que vous devez fsync() le fichier (et son répertoire parent) pour la durabilité . La question est de savoir si le noyau perd des tampons encrés qui sont en attente d'écriture en raison d'une erreur d'E / S, comment l'application peut-elle les détecter et les récupérer ou les abandonner?

Pensez aux applications de base de données, etc., où l'ordre des écritures et la durabilité de l'écriture peuvent être cruciaux.

Lost écrit? Comment?

La couche de bloc du noyau Linux peut dans certaines circonstances perdre des requêtes d'E / S tamponnées qui ont été soumises avec succès par write() , pwrite() etc, avec une erreur comme:

Buffer I/O error on device dm-0, logical block 12345
lost page write due to I/O error on dm-0

(Voir end_buffer_write_sync(...) et end_buffer_async_write(...) dans fs/buffer.c ).

Sur les nouveaux noyaux, l'erreur contiendra à la place "lost async page write" , comme:

Buffer I/O error on dev dm-0, logical block 12345, lost async page write

Puisque l'application write() aura déjà retourné sans erreur, il ne semble pas possible de signaler une erreur à l'application.

Les détecter?

Je ne suis pas très familier avec les sources du noyau, mais je pense qu'il définit AS_EIO sur le tampon qui n'a pas pu être écrit s'il fait une écriture asynchrone:

    set_bit(AS_EIO, &page->mapping->flags);
    set_buffer_write_io_error(bh);
    clear_buffer_uptodate(bh);
    SetPageError(page);

mais il n'est pas clair pour moi si ou comment l'application peut trouver à ce sujet quand il plus tard fsync() s le fichier pour confirmer qu'il est sur le disque.

Il semble que wait_on_page_writeback_range(...) en mm/filemap.c pourrait être fait par do_sync_mapping_range(...) dans fs/sync.c qui est appelé par sys_sync_file_range(...) . Il renvoie -EIO si un ou plusieurs tampons n'ont pas pu être écrits.

Si, comme je le devine, cela se propage au fsync() de fsync() , alors si l'application panique et se retire si elle reçoit une erreur d'E / S de fsync() et sait comment refaire son travail quand elle est redémarrée, cela devrait être une garantie suffisante?

Il n'y a probablement aucun moyen pour l'application de savoir quels décalages d'octets dans un fichier correspondent aux pages perdues afin de pouvoir les réécrire si elle sait comment, mais si l'application répète tout son travail en attente depuis la dernière fsync() du fichier, et qui réécrit tous les tampons de noyau sales correspondant aux écritures perdues contre le fichier, cela devrait effacer tous les drapeaux d'erreur d'E / S sur les pages perdues et permettre au prochain fsync() de compléter - droit?

Y a-t-il alors d'autres circonstances, inoffensives, où fsync() peut revenir - -EIO où le renflouement et la reprise du travail seraient trop drastiques?

Pourquoi?

Bien sûr, de telles erreurs ne devraient pas se produire. Dans ce cas, l'erreur résultait d'une interaction malheureuse entre les valeurs par défaut du pilote dm-multipath et le code de détection utilisé par le réseau de stockage pour signaler l'échec de l'allocation du stockage avec allocation dynamique. Mais ce n'est pas la seule circonstance où ils peuvent se produire - j'ai également vu des rapports à partir de LVM provisionné par exemple, tel qu'utilisé par libvirt, Docker, et plus encore. Une application critique comme une base de données devrait essayer de faire face à de telles erreurs, plutôt que de continuer aveuglément comme si tout allait bien.

Si le noyau pense qu'il est acceptable de perdre des écritures sans mourir avec une panique du noyau, les applications doivent trouver un moyen de s'en sortir.

L'impact pratique est que j'ai trouvé un cas où un problème de multi-chemin avec un SAN a causé des écritures perdues qui ont abouti à la corruption de la base de données parce que le SGBD ne savait pas que ses écritures avaient échoué. Pas drôle.




Utilisez l'indicateur O_SYNC lorsque vous ouvrez le fichier. Il s'assure que les données sont écrites sur le disque.

Si cela ne vous satisfait pas, il n'y aura rien.




Links