{"id":1904,"date":"2011-03-13T23:43:50","date_gmt":"2011-03-13T22:43:50","guid":{"rendered":"http:\/\/blog.capdata.fr\/?p=1904"},"modified":"2019-09-13T14:46:02","modified_gmt":"2019-09-13T13:46:02","slug":"consistence-des-ecritures-avec-sata","status":"publish","type":"post","link":"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/","title":{"rendered":"Consistence des \u00e9critures avec SATA"},"content":{"rendered":"<a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-twitter nolightbox\" data-provider=\"twitter\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Twitter\" href=\"https:\/\/twitter.com\/intent\/tweet?url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1904&#038;text=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"twitter\" title=\"Share on Twitter\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/twitter.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-linkedin nolightbox\" data-provider=\"linkedin\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Linkedin\" href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&#038;url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1904&#038;title=Consistence%20des%20%C3%A9critures%20avec%20SATA\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"linkedin\" title=\"Share on Linkedin\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/linkedin.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-mail nolightbox\" data-provider=\"mail\" rel=\"nofollow\" title=\"Share by email\" href=\"mailto:?subject=Consistence%20des%20%C3%A9critures%20avec%20SATA&#038;body=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20:%20https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1904\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"mail\" title=\"Share by email\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/mail.png\" \/><\/a><p>A l&#8217;origine, cet autre <a href=\"http:\/\/perspectives.mvdirona.com\/2008\/04\/17\/DisksLiesAndDamnDisks.aspx\">post<\/a> de James Hamilton qui s&#8217;interroge sur le support de FUA par le protocole ATA\/IDE\/SATA.<\/p>\n<h2>C&#8217;est quoi FUA ?<\/h2>\n<p>FUA = Force Unit Access. Il s&#8217;agit d&#8217;un bit au sein d&#8217;un Command Disk Block Read ou Write SCSI qui permet d&#8217;indiquer au driver de ne pas lire ou \u00e9crire depuis ou \u00e0 partir d&#8217;un cache mais bien depuis ou \u00e0 partir du m\u00e9dia physique, c&#8217;est \u00e0 dire du disque magn\u00e9tique. Par exemple un CDB de Write(10) (source <a href=\"http:\/\/en.wikipedia.org\/wiki\/SCSI_Write_Commands\">wikipedia<\/a>):<\/p>\n<p><a href=\"http:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/02\/CDB_Write_10_SCSI1.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1909\" title=\"CDB_Write_10_SCSI\" src=\"http:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/02\/CDB_Write_10_SCSI1.jpg\" alt=\"\" width=\"481\" height=\"163\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/02\/CDB_Write_10_SCSI1.jpg 481w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/02\/CDB_Write_10_SCSI1-300x101.jpg 300w\" sizes=\"auto, (max-width: 481px) 100vw, 481px\" \/><\/a><\/p>\n<p>C&#8217;est important d&#8217;avoir cette garantie pour les moteurs de bases de donn\u00e9es car elle leur permet de supporter ce qu&#8217;on appelle le <em>WAL protocol<\/em> , le pilier qui soutient\u00a0 la durabilit\u00e9 des transactions dans un SGBD. Lorsqu&#8217;une transaction est valid\u00e9e, quoi qu&#8217;il advienne ensuite cette information doit \u00eatre physiquement inscrite quelque part sur un m\u00e9dia persistant. M\u00eame si on perd un disque, l&#8217;alimentation de la machine ou toute la salle d&#8217;un seul coup, tout ce qui a \u00e9t\u00e9 modifi\u00e9 avant la validation de cette transaction doit se retrouver sur disque avant fin du COMMIT, d&#8217;o\u00f9 le nom (WAL = Write Ahead Logging).<\/p>\n<p>SQL Server utilise deux commutateurs lors de l&#8217;ouverture des fichiers de donn\u00e9es et des journaux de transactions au d\u00e9marrage de l&#8217;instance pour valider ce comportement (FILE_FLAG_WRITE_THROUGH\u00a0 |\u00a0 FILE_FLAG_NO_BUFFERING). Le premier indique que l&#8217;OS a le droit de bufferiser une \u00e9criture mais qu&#8217;il ne doit pas renvoyer d&#8217;acquittement avant que cette \u00e9criture n&#8217;ait touch\u00e9 le support physique (l&#8217;\u00e9quivalent de O_DSYNC sur Linux, cf ce <a href=\"http:\/\/blog.capdata.fr\/index.php\/sybase-ase-direct-io-dsync-onoff-raw-device\/\">post<\/a>). La seconde indique que l&#8217;Os n&#8217;a pas le droit de lire une donn\u00e9e depuis le cache, mais de forcer la lecture \u00e0 partir du disque. Donc vous l&#8217;aurez compris, l&#8217;association des deux permet de bypasser compl\u00e8tement le cache.<\/p>\n<h2>FUA et SATA:<\/h2>\n<p>Ce bit FUA fait partie int\u00e9grante du protocole SCSI mais reste ignor\u00e9 par ATA et SATA. Lorsque l&#8217;information arrive au driver atapi.sys, elle est tout simplement non interpr\u00e9t\u00e9e, les \u00e9critures vont dans le cache et l&#8217;acquittement OK revient au moteur. Pas terrible pour la durabilit\u00e9 des transactions. La seule arme face au probl\u00e8me reste de d\u00e9sactiver le cache en \u00e9criture au niveau du disque (sous windows une petite case \u00e0 d\u00e9cocher dans les propri\u00e9t\u00e9s du disque, voir au bas de cet article), mais le probl\u00e8me, c&#8217;est qu&#8217;il n&#8217;y a encore aujourd&#8217;hui aucun moyen de savoir r\u00e9ellement si le driver a bien pris en compte cette modification ou non.<\/p>\n<p>Depuis, SATA II a annonc\u00e9 le support de FUA, mais dans la pratique je vois encore beaucoup de :<\/p>\n<pre><span style=\"color: #0000ff;\"><em>sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA<\/em><\/span><\/pre>\n<p>sur les forums linux, m\u00eame avec des contr\u00f4leurs SATA II. Apr\u00e8s une petite discussion avec <a href=\"http:\/\/blogs.msdn.com\/b\/psssql\/\">Bob Dorr<\/a> du support MS, je suis parti \u00e0 la recherche de preuves. J&#8217;ai un laptop avec un disque SATA, un SQL Server 2005 SP3, je voudrais savoir si les \u00e9critures envoy\u00e9es vers le disque seront \u00e9crites dans le cache ou r\u00e9ellement sur le disque. Capture du mat\u00e9riel pour m\u00e9mo:<\/p>\n<p><a href=\"http:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/satadrv.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-2053\" title=\"satadrv\" src=\"http:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/satadrv-300x297.jpg\" alt=\"\" width=\"300\" height=\"297\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/satadrv-300x297.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/satadrv-150x150.jpg 150w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/satadrv-144x144.jpg 144w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/satadrv-50x50.jpg 50w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/satadrv.jpg 324w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<h2>La Descente vers le disque:<\/h2>\n<p>Avant d&#8217;aller plus loin, il faut rappeler un peu la th\u00e9orie des IOs sous Windows, et la relation avec SQL Server.<\/p>\n<p>Lorsque SQL Server d\u00e9marre, il ouvre les fichiers de donn\u00e9es et les journaux de transactions des bases qu&#8217;il monte en ligne avec <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa363858%28v=vs.85%29.aspx\">CreateFile<\/a>. Il r\u00e9cup\u00e8re un type HANDLE qui sera utilis\u00e9 ensuite pour toutes les op\u00e9rations sur le fichier (lectures \/ \u00e9critures). Lorsqu&#8217;un processus demande l&#8217;ouverture ou la cr\u00e9ation d&#8217;un fichier, le noyau transf\u00e8re le contr\u00f4le \u00e0 l&#8217;Object Manager. Celui-ci cr\u00e9\u00e9 un objet de type <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff545834%28v=vs.85%29.aspx\">FILE_OBJECT<\/a> pour d\u00e9crire le fichier, ses attributs, ses modes d&#8217;acc\u00e8s, la liste des IOs en cours, etc.. Lorsque notre CreateFile ouvre un fichier en FILE_FLAG_WRITE_THROUGH, le bit FO_WRITE_THROUGH (0x00000010 *) va \u00eatre ajout\u00e9 au membre .<em>Flags<\/em> du FILE_OBJECT.<\/p>\n<p>Ensuite, lorsque le programme doit\u00a0 \u00e9crire dans le fichier, il utilisera une des primitives <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa365747%28v=vs.85%29.aspx\">WriteFile<\/a>() \/ <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa365748%28v=vs.85%29.aspx\">WriteFileEx<\/a>() \/ <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa365749%28v=vs.85%29.aspx\">WriteFileGather<\/a>().\u00a0 Lors de l&#8217;\u00e9criture, le noyau transf\u00e8re le contr\u00f4le \u00e0 l&#8217;IO Manager pour l&#8217;initialisation de l&#8217;IO. Celui-ci va cr\u00e9er un <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff550694%28v=vs.85%29.aspx\">IRP <\/a>(IO Request Packet) pour d\u00e9crire l&#8217;op\u00e9ration.\u00a0 Chaque IRP a une structure en ascenceur. Elle contient un ent\u00eate et plusieurs piles (une par driver dans la pile de drivers jusqu&#8217;au disque) qu&#8217;on appelle des <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff550659%28v=vs.85%29.aspx\">IO_STACK_LOCATIONs<\/a>. L&#8217;ent\u00eate sert \u00e0 pointer vers l&#8217;IO_STACK_LOCATION correspondant au driver en cours dans la pile. Lorsque le driver courant a termin\u00e9 son op\u00e9ration, il passe l&#8217;IRP au driver suivant dans la stack et fait pointer l&#8217;ent\u00eate de l&#8217;IRP vers l&#8217;IO_STACK_LOCATION suivante, etc&#8230;(cf <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms810023.aspx\">Handling IRPS : what every driver writer needs to know<\/a>).<\/p>\n<p>Chaque IRP renseigne un bitmask (<em>.Flags<\/em>) pour indiquer quels sont les commutateurs actifs. Parmi ceux-ci, SL_WRITE_THROUGH (0x04 *) propage notre contrainte d&#8217;\u00e9criture sur le m\u00e9dia au driver, et c&#8217;est l\u00e0 que les choses se g\u00e2tent.<\/p>\n<p>L&#8217;id\u00e9e est donc de contr\u00f4ler la propagation du writethrough \u00e0 travers les diff\u00e9rentes IO_STACK_LOCATIONS et voir quel driver r\u00e9initialise le bit.<\/p>\n<p>J&#8217;ai tent\u00e9 pendant trois ou quatre jours de traquer la b\u00eate avec livekd, mais c&#8217;est assez difficile de prendre SQL Server la main dans le sac. Les IOs sont assez rapides et les IRP vers les disques sont supprim\u00e9es par l&#8217;IO Manager avant que je n&#8217;aie le temps de les inspecter. J&#8217;ai donc d\u00e9cid\u00e9 (pas born\u00e9 du tout le gar\u00e7on \ud83d\ude09 ) d&#8217;\u00e9crire un petit programme tr\u00e8s simple qui me ferait en boucle des \u00e9critures align\u00e9es sur les secteurs disque en write-through exactement comme SQL Server, avec le c\u00f4t\u00e9 asynchrone en moins (pas important pour ce que l&#8217;on cherche, et en plus pas tr\u00e8s simple \u00e0 g\u00e9rer, mais promis ce sera l&#8217;objet d&#8217;un prochain post).<\/p>\n<p>Le source:<\/p>\n<pre><span style=\"color: #008000;\">\/\/ ------------------------------------------------------------------------------------------------------------\r\n\/\/ writeThrough.cpp\u00a0: Ecrit en boucle des caract\u00e8res dans un fichier en mode Writethrough \/ No Buffering\r\n\/\/ Utilis\u00e9 avec livekd, permet de scruter le contenu des IO_STACK_LOCATION dans l'IRP correspondante\r\n\/\/ pour contr\u00f4ler si le bit SL_WRITE_THROUGH est bien propag\u00e9 jusqu'au driver (pb ATA \/ IDE \/S-ATA).\r\n\/\/\r\n\/\/ On utilisera un IOCTL (IOCTL_DISK_GET_DRIVE_GEOMETRY) pour r\u00e9cup\u00e9rer la taille du secteur\r\n\/\/\r\n\/\/ dbaffaleuf@capdata.fr (c) CapData Consulting 2011\r\n\/\/\r\n\/\/ ------------------------------------------------------------------------------------------------------------<\/span>\r\n\r\n<span style=\"color: #008000;\">#include &lt;stdafx.h&gt;\r\n#include &lt;windows.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;winioctl.h&gt;\r\n#include &lt;direct.h&gt;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">int _tmain(int argc, _TCHAR* argv[])\r\n{\r\n     if (argc!=2)\r\n    {\r\n        printf(\"Usage is:\u00a0 writeThrough outputfilename\\n\");\r\n        return 1;\r\n    }\r\n\r\n <span style=\"color: #008000;\">\/\/ R\u00e9cup\u00e9ration de la taille du secteur disque avec un IOCTL ---------------------------------------------------<\/span>\r\n DISK_GEOMETRY dg;\r\n HANDLE hDrive;\r\n DWORD ioctlJnk; \r\n\r\n hDrive=CreateFile(TEXT(\"\\\\\\\\.\\\\PhysicalDrive0\")\r\n                          ,0\r\n                          ,FILE_SHARE_READ\r\n                          | FILE_SHARE_WRITE\r\n                          ,NULL\r\n                          ,OPEN_EXISTING\r\n                          ,0\r\n                          ,NULL);\r\n\r\n if (INVALID_HANDLE_VALUE==hDrive)\r\n {\r\n     printf(\"Unable to open drive PhysicalDrive0. Last error=%d\\n\",GetLastError());\r\n     return 1;\r\n }\r\n\r\n if (! DeviceIoControl(hDrive\r\n                          ,IOCTL_DISK_GET_DRIVE_GEOMETRY\r\n                          ,NULL\r\n                          ,0\r\n                          ,&amp;dg\r\n                          ,sizeof(dg)\r\n                          ,&amp;ioctlJnk\r\n                          ,NULL) )\r\n {\r\n     printf(\"Error on IOCTL (IOCTL_DISK_GET_DRIVE_GEOMETRY) to %s.\u00a0 Last error=%d\\n\",argv[1],GetLastError());\r\n     return 1;\r\n }\r\n\r\n CloseHandle(hDrive);\r\n\r\n <span style=\"color: #008000;\">\/\/ Ouverture du fichier Writethrough + No Buffering ---------------------------------------------------------<\/span>\r\n HANDLE hOutputFile=CreateFile(argv[1]\r\n                      ,GENERIC_READ\r\n                      | GENERIC_WRITE\r\n                      ,0\r\n                      ,NULL\r\n                      ,CREATE_ALWAYS\r\n                      ,FILE_ATTRIBUTE_NORMAL\r\n                      | FILE_FLAG_WRITE_THROUGH\r\n                      | FILE_FLAG_NO_BUFFERING\r\n                      ,NULL);\r\n\r\n if (INVALID_HANDLE_VALUE==hOutputFile)\r\n {\r\n     printf(\"Unable to open file %s.\u00a0 Last error=%d\\n\",argv[1],GetLastError());\r\n     return 1;\r\n }\r\n\r\n <span style=\"color: #008000;\">\/\/ Initialisation du tampon et \u00e9criture --------------------------------------------------------------------<\/span>\r\n wchar_t *csBuffer = (wchar_t *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dg.BytesPerSector * sizeof(wchar_t));\r\n int len = swprintf_s(csBuffer,dg.BytesPerSector,L\"abcdefghijklmnopqrstuvwxyz\");\u00a0\u00a0 \u00a0\r\n DWORD dwBytesWritten;\r\n DWORD dwTotalBytesWritten=0;\r\n\r\n do\r\n {\r\n     if (! WriteFile(hOutputFile\r\n                       ,csBuffer\r\n                       ,dg.BytesPerSector\r\n                       ,&amp;dwBytesWritten\r\n                       ,NULL))\r\n     {\r\n         printf (\"WriteFile failed with error %d.\\n\", GetLastError());\r\n         return 1;\r\n     }\r\n\r\n    dwTotalBytesWritten+=dwBytesWritten;\r\n    printf(\"Operation termin\u00e9e, %d octets \u00e9crits\\n\", dwTotalBytesWritten);\r\n    Sleep (1);\r\n\r\n } while (TRUE);\r\n\r\n HeapFree(GetProcessHeap(),0,csBuffer);\r\n CloseHandle(hOutputFile);\r\n\r\n return 0;\r\n}<\/span><\/pre>\n<p>La seule contrainte d&#8217;utilisation de (FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH) est d&#8217;\u00e9crire en s&#8217;alignant sur les secteurs du disque, il nous faut donc r\u00e9cup\u00e9rer la taille du secteur avec un <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa363219%28v=vs.85%29.aspx\">IOCTL<\/a> (en l&#8217;occurence <em>IOCTL_DISK_GET_DRIVE_GEOMETRY<\/em>). Dans la plupart des cas ce sera 512 octets, mais des tailles de 4K vont commencer \u00e0 arriver sur le march\u00e9, donc il ne faut pas pr\u00e9sumer et bien calculer tout \u00e7a proprement. Dans la seconde partie, on initialise un buffer sur une taille multiple de la taille du secteur et on \u00e9crit dans notre fichier hOutputFile en boucle continue, avec une pause de 1 ms entre chaque \u00e9criture.<\/p>\n<p>On lance le programme en boucle et on va passer \u00e0 la partie livekd:<\/p>\n<pre><span style=\"color: #0000ff;\"><strong>C:\\DBA\\DEV\\CPP\\writeThrough\\Debug&gt;writeThrough.exe test.txt<\/strong>\r\nOperation termin\u00e9e, 512 octets \u00e9crits\r\nOperation termin\u00e9e, 1024 octets \u00e9crits\r\nOperation termin\u00e9e, 1536 octets \u00e9crits\r\nOperation termin\u00e9e, 2048 octets \u00e9crits\r\nOperation termin\u00e9e, 2560 octets \u00e9crits\r\nOperation termin\u00e9e, 3072 octets \u00e9crits<\/span>\r\n...<\/pre>\n<h2>Observation des IRPs:<\/h2>\n<p>Premi\u00e8re chose \u00e0 faire si vous souhaitez reproduire ce POC, il vous faudra r\u00e9cup\u00e9rer les <a href=\"http:\/\/msdn.microsoft.com\/en-us\/windows\/hardware\/gg463009\">outils de debug de Windows<\/a> et les <a href=\"http:\/\/msdn.microsoft.com\/en-us\/windows\/hardware\/gg463028\">symboles <\/a>pour votre plateforme. Il vous faudra aussi r\u00e9cup\u00e9rer <a href=\"http:\/\/technet.microsoft.com\/en-us\/sysinternals\/bb897415\">LiveKD<\/a>.<\/p>\n<p>Ensuite pointer vers le serveur de symboles MS:<\/p>\n<pre><span style=\"color: #0000ff;\">set _NT_SYMBOL_PATH=srv*c:\\temp\\symbols*http:\/\/msdl.microsoft.com\/download\/symbols\u00a0\u00a0 <\/span><\/pre>\n<p>Et lancer livekd. Pour assurer un peu plus la coh\u00e9rence des r\u00e9sultats, il peut \u00eatre n\u00e9cessaire de passer par un bcdedit \/debug on + reboot pour activer le d\u00e9bogage du noyau. La strat\u00e9gie est de retrouver les IRPs actives associ\u00e9es au fichier dans lequel on \u00e9crit par le biais d&#8217;un !irpfind en lui passant l&#8217;adresse du DEVICE_OBJECT associ\u00e9 au disque. Dans un foreach, ensuite on affiche le contenu d\u00e9taill\u00e9 de toutes les irps que l&#8217;on retrouve. Attention, vous devrez sans doute le faire un certain nombre de fois pour pouvoir observer un IRP d\u00e9crivant une \u00e9criture (MAJOR= 4 =&gt; IRP_MJ_WRITE).<\/p>\n<p>Premi\u00e8re chose, on va r\u00e9cup\u00e9rer l&#8217;adresse de notre processus writeThrough.exe, et le passer en process par d\u00e9faut sous livekd:<\/p>\n<pre><span style=\"color: #0000ff;\">lkd&gt; !sym quiet\r\nquiet mode - symbol prompts on<\/span><\/pre>\n<pre><span style=\"color: #0000ff;\">lkd&gt; !process 0 0 writeThrough.exe\r\nPROCESS <span style=\"color: #008000;\">881b39d0\u00a0 <\/span>SessionId: 0\u00a0 Cid: 0c08\u00a0\u00a0\u00a0 Peb: 7ffde000\u00a0 ParentCid: 0960\r\n DirBase: 0aa80740\u00a0 ObjectTable: e4168638\u00a0 HandleCount:\u00a0\u00a0 9.\r\n Image: writeThrough.exe\r\n<\/span>\r\n<span style=\"color: #0000ff;\">lkd&gt; .process <span style=\"color: #008000;\">881b39d0 \u00a0<\/span>\r\nImplicit process is now 881b39d0\r\n<\/span><\/pre>\n<p>Ensuite, nous allons nous int\u00e9resser au fichier test.txt. Il nous faut r\u00e9cup\u00e9rer le FILE_OBJECT cr\u00e9\u00e9 par l&#8217;Object Manager lors du CreateFile():<\/p>\n<pre><span style=\"color: #0000ff;\">0: kd&gt; !handle 0 3\r\n(...)\r\n07dc: Object: <span style=\"color: #008000;\">8701f1b0\u00a0 <\/span>GrantedAccess: 0012019f Entry: e3baefb8\r\nObject: 8701f1b0\u00a0 Type: (8a57a900) File\r\n ObjectHeader: 8701f198 (old version)\r\n HandleCount: 1\u00a0 PointerCount: 1\r\n Directory Object: 00000000\u00a0 Name: \\CAPDATA\\DEV\\DEV++\\writeThrough\\Debug\\test.txt {HarddiskVolume3}\r\n(...)\r\n\r\n0: kd&gt; dt nt!_FILE_OBJECT <span style=\"color: #008000;\">8701f1b0<\/span>\r\n +0x000 Type\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0n5\r\n +0x002 Size\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0n112\r\n<span style=\"color: #008000;\"> +0x004 DeviceObject\u00a0\u00a0\u00a0\u00a0 : <\/span><\/span><span style=\"color: #008000;\">0x8a4a5a30<\/span><span style=\"color: #0000ff;\"><span style=\"color: #008000;\">_DEVICE_OBJECT<\/span>\r\n +0x008 Vpb\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0x8a4a71e8 _VPB\r\n +0x00c FsContext\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0xe6be4928 Void\r\n +0x010 FsContext2\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0xe6be4a80 Void\r\n +0x014 SectionObjectPointer : 0x8839f5cc _SECTION_OBJECT_POINTERS\r\n +0x018 PrivateCacheMap\u00a0 : (null)\r\n +0x01c FinalStatus\u00a0\u00a0\u00a0\u00a0\u00a0 : 0n0\r\n +0x020 RelatedFileObject : 0x88752ec0 _FILE_OBJECT\r\n +0x024 LockOperation\u00a0\u00a0\u00a0 : 0 ''\r\n +0x025 DeletePending\u00a0\u00a0\u00a0 : 0 ''\r\n +0x026 ReadAccess\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0x1 ''\r\n +0x027 WriteAccess\u00a0\u00a0\u00a0\u00a0\u00a0 : 0x1 ''\r\n +0x028 DeleteAccess\u00a0\u00a0\u00a0\u00a0 : 0 ''\r\n +0x029 SharedRead\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0 ''\r\n +0x02a SharedWrite\u00a0\u00a0\u00a0\u00a0\u00a0 : 0 ''\r\n +0x02b SharedDelete\u00a0\u00a0\u00a0\u00a0 : 0 ''\r\n<span style=\"color: #008000;\"> +0x02c Flags\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0x4101a<\/span>\r\n +0x030 FileName\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : _UNICODE_STRING \"\\CAPDATA\\DEV\\DEV++\\writeThrough\\Debug\\test.txt\"\r\n +0x038 CurrentByteOffset : _LARGE_INTEGER 0x7c00\r\n +0x040 Waiters\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0\r\n +0x044 Busy\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0\r\n +0x048 LastLock\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : (null)\r\n +0x04c Lock\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : _KEVENT\r\n +0x05c Event\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : _KEVENT\r\n +0x06c CompletionContext : (null)\r\n\r\n<\/span><\/pre>\n<p>Par la m\u00eame occasion, on va v\u00e9rifier si notre CreateFile() a bien propag\u00e9 FO_WRITE_THROUGH au FILE_OBJECT:<\/p>\n<pre><span style=\"color: #0000ff;\">0: kd&gt; ? (<span style=\"color: #008000;\">0x4101a <\/span>&amp; 0x00000010)\r\nEvaluate expression: 16 = 00000010<\/span><\/pre>\n<p>OK. On peut donc poursuivre en gardant sous le coude l&#8217;adresse du DEVICE OBJECT renvoy\u00e9 par le dt nt!_FILE_OBJECT&#8230; :<\/p>\n<pre><span style=\"color: #008000;\">(...)\r\n+0x004 DeviceObject\u00a0\u00a0\u00a0\u00a0 : <strong>0x8a4a5a30<\/strong>_DEVICE_OBJECT\r\n(...)<\/span><\/pre>\n<h2>Courage !<\/h2>\n<p>Et c&#8217;est l\u00e0 que la partie de p\u00eache commence vraiment. Je vous laisse le soin de regarder comment les instructions sous un d\u00e9boggeur fonctionnent mais l&#8217;id\u00e9e est de r\u00e9cup\u00e9rer l&#8217;adresse de chaque IRP associ\u00e9e au DEVICE OBJECT de notre disque et d&#8217;afficher son contenu, en v\u00e9rifiant qu&#8217;il provient bien de notre petit programme. Il faut \u00eatre patient. Au bout d&#8217;un certain nombre de tentatives, on arrive \u00e0 en attraper une :<\/p>\n<pre><span style=\"color: #0000ff;\">lkd&gt; .foreach \/pS 1 \/ps 3 (irpaddr {.foreach \/pS 21 \/ps 9 (irpaddressblk {!irpfind 0 0 device <span style=\"color: #008000;\">0x8a4a5a30<\/span>}) { .echo ${irpaddressblk} } }) { !irp ${irpaddr} 1 }\r\nIrp is active with 10 stacks 6 is current (= 0x882a312c)\r\n Mdl=88195a60: No System Buffer: Thread 881059e8:\u00a0 Irp stack trace. \u00a0\r\n<span style=\"color: #008000;\">Flags = 00000043<\/span>\r\nThreadListEntry.Flink = 882a3018\r\nThreadListEntry.Blink = 882a3018\r\nIoStatus.Status = 00000000\r\nIoStatus.Information = 00000000\r\nRequestorMode = 00000000\r\nCancel = 00\r\nCancelIrql = 0\r\nApcEnvironment = 00\r\nUserIosb = a0e60878\r\nUserEvent = a0e60820\r\nOverlay.AsynchronousParameters.UserApcRoutine = 00000000\r\nOverlay.AsynchronousParameters.UserApcContext = 00000000\r\nOverlay.AllocationSize = 00000000 - 00000000\r\nCancelRoutine = 00000000\u00a0 \u00a0\r\nUserBuffer = 88083000\r\n&amp;Tail.Overlay.DeviceQueueEntry = 882a3048\r\nTail.Overlay.Thread = 881059e8\r\nTail.Overlay.AuxiliaryBuffer = 00000000\r\nTail.Overlay.ListEntry.Flink = 00000000\r\nTail.Overlay.ListEntry.Blink = 00000000\r\nTail.Overlay.CurrentStackLocation = 882a312c\r\nTail.Overlay.OriginalFileObject = 899ef028\r\nTail.Apc = 00000000\r\nTail.CompletionKey = 00000000\r\n cmd\u00a0 flg cl Device\u00a0\u00a0 File\u00a0\u00a0\u00a0\u00a0 Completion-Context\r\n [\u00a0 0, 0]\u00a0\u00a0 0\u00a0 0 00000000 00000000 00000000-00000000\u00a0\u00a0 \u00a0\r\n\r\n Args: 00000000 00000000 00000000 00000000\r\n [\u00a0 0, 0]\u00a0\u00a0 0\u00a0 0 00000000 00000000 00000000-00000000\u00a0\u00a0 \u00a0\r\n\r\n Args: 00000000 00000000 00000000 00000000\r\n [\u00a0 0, 0]\u00a0\u00a0 0\u00a0 0 00000000 00000000 00000000-00000000\u00a0\u00a0 \u00a0\r\n\r\n Args: 00000000 00000000 00000000 00000000\r\n [\u00a0 0, 0]\u00a0\u00a0 0\u00a0 0 00000000 00000000 00000000-00000000\u00a0\u00a0 \u00a0\r\n\r\n Args: 00000000 00000000 00000000 00000000\r\n [\u00a0 0, 0]\u00a0\u00a0 0\u00a0 0 00000000 00000000 00000000-00000000\u00a0\u00a0 \u00a0\r\n\r\n Args: 00000000 00000000 00000000 00000000\r\n<span style=\"color: #008000;\">&gt;[\u00a0 4, 0]\u00a0\u00a0 0\u00a0 0 8a483770 00000000 f77077ca-8a483548\u00a0\u00a0 \u00a0\r\n \\Driver\\Disk\u00a0\u00a0 \u00a0\r\n Args: 00000000 00000000 00000000 00000000<\/span>\r\n [\u00a0 4, 0]\u00a0\u00a0 0\u00a0 0 8a483548 00000000 f7238962-8a4a5ae8\u00a0\u00a0 \u00a0\r\n \\Driver\\PartMgr\u00a0\u00a0 \u00a0\r\n Args: 00000000 00000000 00000000 00000000\r\n [\u00a0 4, 0]\u00a0\u00a0 0\u00a0 0 8a4a5a30 00000000 f74a7680-8a48a7b8\u00a0\u00a0 \u00a0\r\n \\Driver\\Ftdisk\u00a0\u00a0 \u00a0\r\n Args: 00000000 00000000 00000000 00000000\r\n [\u00a0 4, 0]\u00a0\u00a0 0\u00a0 0 8a48a700 00000000 f7063e3f-a0e6045c\u00a0\u00a0 \u00a0\r\n \\Driver\\VolSnap\u00a0\u00a0 \u00a0\r\n Args: 00000000 00000000 00000000 00000000\r\n [\u00a0 4, 0]\u00a0\u00a0 0\u00a0 0 8979c020 00000000 00000000-00000000\u00a0\u00a0 \u00a0\r\n \\FileSystem\\Ntfs\r\n Args: 00000000 00000000 00000000 00000000<\/span><\/pre>\n<p>J&#8217;ai volontairement colori\u00e9 le membre .Flags et l&#8217;IO_STACK_LOCATION courante. On voit bien ici l&#8217;empilement des drivers: Ntfs -&gt; VolSnap -&gt; Ftdisk -&gt; PartMgr -&gt; Disk. Entre crochets, notre couple [MAJOR,Minor] qui indique le type d&#8217;op\u00e9ration en cours (pour plus d&#8217;infos cf l&#8217;aide de la commande !irp dans le <a href=\"http:\/\/msdn.microsoft.com\/en-us\/windows\/hardware\/gg487428\">DDK<\/a>). [4,0] indique que la commande en cours est un IRP_MJ_WRITE, donc une \u00e9criture, et la petite indirection \u00e0 l&#8217;extr\u00eame gauche montre que la besogne est entre les mains du driver le plus bas dans la stack (c:\\Windows\\system32\\Disk.sys). Quant \u00e0 la valeur de .Flags:<\/p>\n<pre><span style=\"color: #0000ff;\">lkd&gt; ? (0x00000043 &amp; 0x4)\r\nEvaluate expression: 0 = 00000000<\/span><\/pre>\n<p>Bingo. Pas de SL_WRITE_THROUGH. J&#8217;ai p\u00fb faire le test avec et sans cache activ\u00e9 au niveau du disque, et le r\u00e9sultat est le m\u00eame:<\/p>\n<p><a href=\"http:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/cacheactivation.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-2063\" title=\"cacheactivation\" src=\"http:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/cacheactivation-282x300.jpg\" alt=\"\" width=\"282\" height=\"300\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/cacheactivation-282x300.jpg 282w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/cacheactivation-283x300.jpg 283w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/cacheactivation.jpg 437w\" sizes=\"auto, (max-width: 282px) 100vw, 282px\" \/><\/a><\/p>\n<p>Donc potentiellement si je d\u00e9branche ma batterie et que je coupe mon alimentation au moment d&#8217;une grosse \u00e9criture il y a un risque de perdre une transaction valid\u00e9e. Je vous avoue que je ne l&#8217;ai test\u00e9 qu&#8217;une seule fois (je tiens aussi un peu \u00e0 mon mat\u00e9riel), mais la coupure est intervenue quelques millisecondes avant le commit, et SQL Server a rollback\u00e9 tout \u00e7a proprement. Il faudrait faire une batterie de tests mais je n&#8217;ai pas les moyens de cramer du disque comme \u00e7a. Apr\u00e8s, cel\u00e0 jette tout de m\u00eame de lourds soup\u00e7ons sur la capacit\u00e9 de SATA \u00e0 r\u00e9pondre aux besoins des SGBD.<\/p>\n<p>Ce n&#8217;est plus qu&#8217;une question de co\u00fbt ou de performance que de comparer SCSI \u00e0 SATA. Cel\u00e0 devient une question d&#8217;int\u00e9grit\u00e9 des donn\u00e9es, et donc un probl\u00e8me fondamental. Affaire \u00e0 suivre&#8230;<\/p>\n<p>A+. David B.<\/p>\n<p><em>* Sources: winddk.h<\/em><\/p>\n<p><em>R\u00e9f\u00e9rences:<br \/>\n<a href=\"http:\/\/support.microsoft.com\/kb\/234656\">http:\/\/support.microsoft.com\/kb\/234656<\/a><br \/>\n<a href=\"http:\/\/support.microsoft.com\/kb\/46091\">http:\/\/support.microsoft.com\/kb\/46091<\/a><br \/>\n<a href=\"http:\/\/support.microsoft.com\/kb\/86903\">http:\/\/support.microsoft.com\/kb\/86903<\/a><\/em><\/p>\n<a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-twitter nolightbox\" data-provider=\"twitter\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Twitter\" href=\"https:\/\/twitter.com\/intent\/tweet?url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1904&#038;text=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"twitter\" title=\"Share on Twitter\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/twitter.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-linkedin nolightbox\" data-provider=\"linkedin\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Linkedin\" href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&#038;url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1904&#038;title=Consistence%20des%20%C3%A9critures%20avec%20SATA\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"linkedin\" title=\"Share on Linkedin\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/linkedin.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-mail nolightbox\" data-provider=\"mail\" rel=\"nofollow\" title=\"Share by email\" href=\"mailto:?subject=Consistence%20des%20%C3%A9critures%20avec%20SATA&#038;body=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20:%20https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F1904\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"mail\" title=\"Share by email\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/mail.png\" \/><\/a>","protected":false},"excerpt":{"rendered":"<p>A l&#8217;origine, cet autre post de James Hamilton qui s&#8217;interroge sur le support de FUA par le protocole ATA\/IDE\/SATA. C&#8217;est quoi FUA ? FUA = Force Unit Access. Il s&#8217;agit d&#8217;un bit au sein d&#8217;un Command Disk Block Read ou&hellip; <a href=\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/\" class=\"more-link\">Continuer la lecture <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":2053,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[173,5],"tags":[187,188],"class_list":["post-1904","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-operating-system","category-sqlserver","tag-fua","tag-sata"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v20.8 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Consistence des \u00e9critures avec SATA - Capdata TECH BLOG<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Consistence des \u00e9critures avec SATA - Capdata TECH BLOG\" \/>\n<meta property=\"og:description\" content=\"A l&#8217;origine, cet autre post de James Hamilton qui s&#8217;interroge sur le support de FUA par le protocole ATA\/IDE\/SATA. C&#8217;est quoi FUA ? FUA = Force Unit Access. Il s&#8217;agit d&#8217;un bit au sein d&#8217;un Command Disk Block Read ou&hellip; Continuer la lecture &rarr;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/\" \/>\n<meta property=\"og:site_name\" content=\"Capdata TECH BLOG\" \/>\n<meta property=\"article:published_time\" content=\"2011-03-13T22:43:50+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-09-13T13:46:02+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/satadrv.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"324\" \/>\n\t<meta property=\"og:image:height\" content=\"321\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"David Baffaleuf\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u00c9crit par\" \/>\n\t<meta name=\"twitter:data1\" content=\"David Baffaleuf\" \/>\n\t<meta name=\"twitter:label2\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/\"},\"author\":{\"name\":\"David Baffaleuf\",\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/person\/136297da9f61d6e4878abe0f48bc5fbf\"},\"headline\":\"Consistence des \u00e9critures avec SATA\",\"datePublished\":\"2011-03-13T22:43:50+00:00\",\"dateModified\":\"2019-09-13T13:46:02+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/\"},\"wordCount\":1728,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/blog.capdata.fr\/#organization\"},\"keywords\":[\"FUA\",\"SATA\"],\"articleSection\":[\"Operating System\",\"SQL Server\"],\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/\",\"url\":\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/\",\"name\":\"Consistence des \u00e9critures avec SATA - Capdata TECH BLOG\",\"isPartOf\":{\"@id\":\"https:\/\/blog.capdata.fr\/#website\"},\"datePublished\":\"2011-03-13T22:43:50+00:00\",\"dateModified\":\"2019-09-13T13:46:02+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/#breadcrumb\"},\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/blog.capdata.fr\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Consistence des \u00e9critures avec SATA\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.capdata.fr\/#website\",\"url\":\"https:\/\/blog.capdata.fr\/\",\"name\":\"Capdata TECH BLOG\",\"description\":\"Le blog technique sur les bases de donn\u00e9es de CAP DATA Consulting\",\"publisher\":{\"@id\":\"https:\/\/blog.capdata.fr\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.capdata.fr\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"fr-FR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/blog.capdata.fr\/#organization\",\"name\":\"Capdata TECH BLOG\",\"url\":\"https:\/\/blog.capdata.fr\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp\",\"contentUrl\":\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp\",\"width\":800,\"height\":254,\"caption\":\"Capdata TECH BLOG\"},\"image\":{\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.linkedin.com\/company\/cap-data-consulting\/mycompany\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/person\/136297da9f61d6e4878abe0f48bc5fbf\",\"name\":\"David Baffaleuf\",\"sameAs\":[\"http:\/\/www.capdata.fr\"],\"url\":\"https:\/\/blog.capdata.fr\/index.php\/author\/dbaffaleuf\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Consistence des \u00e9critures avec SATA - Capdata TECH BLOG","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/","og_locale":"fr_FR","og_type":"article","og_title":"Consistence des \u00e9critures avec SATA - Capdata TECH BLOG","og_description":"A l&#8217;origine, cet autre post de James Hamilton qui s&#8217;interroge sur le support de FUA par le protocole ATA\/IDE\/SATA. C&#8217;est quoi FUA ? FUA = Force Unit Access. Il s&#8217;agit d&#8217;un bit au sein d&#8217;un Command Disk Block Read ou&hellip; Continuer la lecture &rarr;","og_url":"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/","og_site_name":"Capdata TECH BLOG","article_published_time":"2011-03-13T22:43:50+00:00","article_modified_time":"2019-09-13T13:46:02+00:00","og_image":[{"width":324,"height":321,"url":"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2011\/03\/satadrv.jpg","type":"image\/jpeg"}],"author":"David Baffaleuf","twitter_card":"summary_large_image","twitter_misc":{"\u00c9crit par":"David Baffaleuf","Dur\u00e9e de lecture estim\u00e9e":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/#article","isPartOf":{"@id":"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/"},"author":{"name":"David Baffaleuf","@id":"https:\/\/blog.capdata.fr\/#\/schema\/person\/136297da9f61d6e4878abe0f48bc5fbf"},"headline":"Consistence des \u00e9critures avec SATA","datePublished":"2011-03-13T22:43:50+00:00","dateModified":"2019-09-13T13:46:02+00:00","mainEntityOfPage":{"@id":"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/"},"wordCount":1728,"commentCount":2,"publisher":{"@id":"https:\/\/blog.capdata.fr\/#organization"},"keywords":["FUA","SATA"],"articleSection":["Operating System","SQL Server"],"inLanguage":"fr-FR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/","url":"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/","name":"Consistence des \u00e9critures avec SATA - Capdata TECH BLOG","isPartOf":{"@id":"https:\/\/blog.capdata.fr\/#website"},"datePublished":"2011-03-13T22:43:50+00:00","dateModified":"2019-09-13T13:46:02+00:00","breadcrumb":{"@id":"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/#breadcrumb"},"inLanguage":"fr-FR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.capdata.fr\/index.php\/consistence-des-ecritures-avec-sata\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/blog.capdata.fr\/"},{"@type":"ListItem","position":2,"name":"Consistence des \u00e9critures avec SATA"}]},{"@type":"WebSite","@id":"https:\/\/blog.capdata.fr\/#website","url":"https:\/\/blog.capdata.fr\/","name":"Capdata TECH BLOG","description":"Le blog technique sur les bases de donn\u00e9es de CAP DATA Consulting","publisher":{"@id":"https:\/\/blog.capdata.fr\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.capdata.fr\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"fr-FR"},{"@type":"Organization","@id":"https:\/\/blog.capdata.fr\/#organization","name":"Capdata TECH BLOG","url":"https:\/\/blog.capdata.fr\/","logo":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/","url":"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp","contentUrl":"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp","width":800,"height":254,"caption":"Capdata TECH BLOG"},"image":{"@id":"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/company\/cap-data-consulting\/mycompany\/"]},{"@type":"Person","@id":"https:\/\/blog.capdata.fr\/#\/schema\/person\/136297da9f61d6e4878abe0f48bc5fbf","name":"David Baffaleuf","sameAs":["http:\/\/www.capdata.fr"],"url":"https:\/\/blog.capdata.fr\/index.php\/author\/dbaffaleuf\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts\/1904","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/comments?post=1904"}],"version-history":[{"count":150,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts\/1904\/revisions"}],"predecessor-version":[{"id":7926,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts\/1904\/revisions\/7926"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/media\/2053"}],"wp:attachment":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/media?parent=1904"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/categories?post=1904"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/tags?post=1904"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}