Hi!
Ich habe einen Mikrocontroller mit USB 2, der (in Software) das
Interface für eine virtuelle serielle Schnittstelle implementiert. Wenn
ich mit dem Mikrocontroller sehr schnell Daten auf die Schnittstelle
schreibe, dann kommen die auf der anderen Seite irgendwie nicht mehr
alle an (nach ein paar MB fehlen immer mal ein paar Pakete, ziemlich
zufällig). Der Code, der die Daten liest, ist denkbar einfach (Python):
Schreibt man nur ein bisschen langsamer, tritt der Fehler nicht mehr
auf.
Klar, jetzt denkt man natürlich, bestimmt wird der Write-Buffer auf dem
Mikrocontroller neu befüllt bevor er leer ist oder so. Aber nein: Wenn
ich mit Wireshark den Traffic auf der USB-Schnittstelle mitschneide,
sind die Pakete alle da! Nur aus /dev/ttyACM0 purzeln nicht alle Daten
wieder raus.
Es klingt blöd, aber das hört sich fast nach einem Fehler in cdc-acm im
Linux-Kernel an, oder? Mir fällt keine andere Erklärung ein. Hat jemand
andere Ideen?
Danke und viele Grüße,
Sven
Deine Hypothese kannst Du durch Verwendung eines anderen Betriebssystems
(Windows, FreeBSD,...) erhärten oder widerlegen.
Was für einen "Mikrocontroller mit USB 2" hast Du denn? Doch nicht etwa
diesen VUSB-Mist?
fchk
Hi,
ne, kein V-USB, der Controller ist ein LPC43xx mit einem ganz normalen
Hardware USB2-Controller.
Ja, anderes Betriebssystem ... werde ich wohl versuchen müssen.
Viele Grüße,
Sven
Sven B. schrieb:> Schreibt man nur ein bisschen langsamer, tritt der Fehler nicht mehr> auf.
Ich sehe nirgends eine Absicherung der Datenübertragung, z.B. durch eine
Prüfsumme, und kein Protokoll, das bei Fehlern die Übertragung neu
anfordert - das ist bei externen Übetragungen über Schnittstellen
generell nicht zu verantworten.
Georg
Georg schrieb:> Ich sehe nirgends eine Absicherung der Datenübertragung, z.B. durch eine> Prüfsumme, und kein Protokoll, das bei Fehlern die Übertragung neu> anfordert - das ist bei externen Übetragungen über Schnittstellen> generell nicht zu verantworten.
was hier aber absolut keine Rolle spielt. Er will wissen warum die Daten
verloren gehen. Da er scheinbar festgestellt hat das Daten fehlen,
scheint es eine "Prüfung" zu geben.
Oder gibt du dich damit zu frieden, ein perfektes Protokoll geschrieben
zu haben was über eine 100Mbit/s Leitung nur 5byte/s schafft, Hauptsache
es geht nicht verloren?
Georg schrieb:> Ich sehe nirgends eine Absicherung der Datenübertragung, z.B. durch eine> Prüfsumme, und kein Protokoll, das bei Fehlern die Übertragung neu> anfordert - das ist bei externen Übetragungen über Schnittstellen> generell nicht zu verantworten.
?
Das ist ein USB-Bulk-Endpoint. Der garantiert mir laut Spezifikation,
dass die Daten vollständig und fehlerfrei übertragen werden. Prüfsummen
und das Erkennen fehlender Pakete sind schon auf USB-Protokoll-Ebene
implementiert und es ist ziemlich sinnlos, das noch einmal auf höhrer
Ebene draufzusetzen. Eigentlich.
> Da er scheinbar festgestellt hat das Daten fehlen,> scheint es eine "Prüfung" zu geben.
Genau, jedes Paket hat einen Header mit ein paar magischen Zeichen am
Anfang, und die sind irgendwann nicht mehr da wo sie sein sollten.
Prüfsumme gibt es wie gesagt keine, ich kann die in dem Tempo nicht
ausrechnen und es darf auch einfach nicht nötig sein.
Sven B. schrieb:> Das ist ein USB-Bulk-Endpoint. Der garantiert mir laut Spezifikation,> dass die Daten vollständig und fehlerfrei übertragen werden. Prüfsummen> und das Erkennen fehlender Pakete sind schon auf USB-Protokoll-Ebene> implementiert und es ist ziemlich sinnlos, das noch einmal auf höhrer> Ebene draufzusetzen. Eigentlich.
das würde ich nicht sagen. Wenn du die Daten aus ttyACM0 nicht schnell
genug aufragst, dann können sie auch verloren gehen.
Peter II schrieb:> das würde ich nicht sagen. Wenn du die Daten aus ttyACM0 nicht schnell> genug aufragst, dann können sie auch verloren gehen.
Das ist genau die Frage, die mich seit längerem beschäftigt. Ist das so?
Ich glaube nicht: Wenn der Buffer voll ist, sollte der Host keine
weiteren Pakete mehr annehmen, und soweit ich das sehen kann ist das
auch das was passiert: Wenn man nur Daten anfragt aber nicht liest dann
werden ein paar übertragen, und danach hängt der uC in der "warte auf
`Endpoint bereit'"-Schleife fest.
Sven B. schrieb:> Das ist genau die Frage, die mich seit längerem beschäftigt. Ist das so?> Ich glaube nicht: Wenn der Buffer voll ist, sollte der Host keine> weiteren Pakete mehr annehmen,
Das sollte sich ja zumindest gut testen lassen. Ich kenne es nur von den
USB-Seriell Adaptern, da gehen schon mal Daten verloren. Keine Ahnung ob
sie CDC verwenden.
Mach doch mal ein paar sleeps in dein PC-Programm und schau ob es
schlimmer wird.
Hab ich schon getestet, wird es nicht. Es dauert dann nur so lange, dass
ich nicht weiß ob der Fehler auftritt (das passiert nur so alle 100000
Pakete mal, und wenn ich nach jedem Paket eine halbe Sekunde warte ...
naja). Umgekehrt ist es aber so, wenn man im Mikrocontroller kurze
Sleeps einbaut, wird es besser bzw. geht ganz weg. Es muss also schon
irgendwas mit dem Timing zu tun haben. Aber der Fehler muss irgendwo
nach dem Linux-USB-Subsystem auftreten, denn da sind die Pakete ja
alle noch da. Also entweder im cdc_acm-Treiber, oder in meinem Programm.
Mit dem Debugger sehe ich, dass der uC während der Host schälft in
seiner "warte bis der Endpoint frei ist"-Schleife festhängt, wie es sein
sollte.
Sven B. schrieb:> Mit dem Debugger sehe ich, dass der uC während der Host schälft in> seiner "warte bis der Endpoint frei ist"-Schleife festhängt, wie es sein> sollte.
Das mag ja sein. Aber was passiert, wenn der Host nicht 'schläft'?
Naja, er nimmt die Daten vom Microcontroller entgegen und schreibt sie
in den Datenpuffer. Der Datenpuffer hat (ich rede mal von Windows, bei
Linux wirds wohl genauso sein) eine bestimmte Größe, z.B. 64 kBytes.
Ausserdem ist der Datenpuffer als Ringpuffer organisiert.
Der Host geht also her und schreibt die Daten in den Ringpuffer. Wenn Du
diese nicht rechtzeitig abholst, dann werden sie eben überschrieben und
es fehlen ein paar kBytes.
Es ist dem Host nämlich ziemlich egal, was mit den Daten passiert. Sein
Job ist es nur, sie in den Ringpuffer zu schreiben.
Der Applikation ist es nicht egal, ob die Daten überschrieben werden
oder nicht. Und genau da kommt dann der Programmierer ins Spiel - also
Du.
Gruß Klaus
Moment, mal langsam.
Wer ist denn für dich "der Host"? Da gibt es mindestens 4 Komponenten:
Den USB-Hostcontroller mit seinem Hardware-Buffer; das
Linux-USB-Subsystem; den cdc_acm-Treiber; und mein Programm. Wie ich das
sehe garantieren 1), 2) und 4) für einen Bulk-Endpoint auf jeden Fall,
dass alle Daten ankommen. Für die virtuelle serielle Schnittstelle bin
ich mir nicht ganz sicher, aber ich war bisher auch der Meinung, dass da
eigentlich nichts verloren gehen darf.
Ich wiederhole nochmal: Wenn ich den uC einfach Daten in den
Endpoint-Buffer schreiben lasse so schnell er kann, dann aber immer
warte, bis die Übertragung abgeschlossen ist (und das tue ich), dann
schreibt der den nur einmal voll und wartet, bis der Host die Daten
abgeholt hat und bereit ist, neue zu empfangen, bevor er da wieder was
reinschreibt. Der einzige Fall, wo mMn Daten verloren gehen können wenn
irgendwas nicht schnell genug ist, ist wenn der uC keinen Speicher mehr
hat um die ganzen Daten, die er zum Senden buffert, zwischenzuspeichern.
Das kommt auch vor, aber ich habe das so implementiert dass dabei immer
nur ganze Pakete verloren gehen, das ist nicht der Grund für den hier
beobachteten Fehler.
"Der Host schläft" heißt übrigens, dass 4) schläft. Auf 1), 2) und 3)
hat das keinen Einfluss.
Sven B. schrieb:> while len(buf) < sz:> buf += os.read(self.fd, sz-len(buf))
Ich kann kein Python, daher verzeihe man mir, wenn das eine blöde Frage
ist:
Wenn per USB kein ganzes Paket der Länge sz vorhanden ist, kommt die
while-loop zum tragen.
In C wäre dies:
Das read liest ein paar Byte und setzt buf ans Ende. Damit liefert
len(buf) immer 0 und das nächste read() schreibt dann hinter dem Puffer
weiter, da dieser keine Länge sz mehr hat.
Steffen R. schrieb:> Sven B. schrieb:>> while len(buf) < sz:>> buf += os.read(self.fd, sz-len(buf))>> Ich kann kein Python, daher verzeihe man mir, wenn das eine blöde Frage> ist:> Wenn per USB kein ganzes Paket der Länge sz vorhanden ist, kommt die> while-loop zum tragen.> In C wäre dies:> Das read liest ein paar Byte und setzt buf ans Ende. Damit liefert> len(buf) immer 0 und das nächste read() schreibt dann hinter dem Puffer> weiter, da dieser keine Länge sz mehr hat.
Das hab' ich leider nicht ganz verstanden, was meinst du? Das os.read()
liest bis zu sz-len(buf) Bytes aus self.fd. Die gelesenen Bytes werden
an buf angehängt. Das wird solange wiederholt, bis buf die Länge sz hat.
Ich find auf merkwüdig das du mit "os.O_NONBLOCK" arbeitest und dann ein
einer schleife so lange liest bis alle zeichen da sind. Da kann man doch
gleich blockieren.
Aber das dürfte dein Problem nicht lösen.
Sven B. schrieb:> Das hab' ich leider nicht ganz verstanden, was meinst du?
Die Frage ist, ob die Zeile das tut, was sie soll, wenn der erste read()
nur ein paar Bytes liest.
Stochern im Nebel an Stellen, welche häufig zu Fehlern führen.
Die offensichtlichen Sachen hast Du ja selbst schon geprüft.
Konnte leider die genaue Erklärung für os.open() nicht finden. Wird die
Schnittstelle im Binärmode geöffnet? Ansonsten könnten die fehlenden
Zeichen Steuerzeichen sein.
Daran liegt's nicht, ich verwende sonst auch das serial.Serial-Modul,
das verhält sich genau gleich. Es fehlen ja auch nicht gelegentlich
einzelne Zeichen -- die Daten sind ziemlich homogen und es werden 50 MB
fehlerfrei übertragen und dann fehlen plötzlich genau 4kB oder sowas.
Aber danke für den Vorschlag.
Hier mal ein bisschen Beispiel-Code, den ich gerade noch gebaut habe, um
das Problem möglichst minimal zu reproduzieren. Der Code überträgt immer
dieselben 12kB Daten mit einer fortlaufenden Sequenznummer am Anfang.
765 mal funktioniert das im Beispiel, beim 766ten Mal (ändert sich
zufällig) fehlt was. In Wireshark sind alle Pakete hintereinander so
verhanden wie man's erwarten würde. Sehr merkwürdig.
uC:
Sven B. schrieb:> Wenn> ich mit Wireshark den Traffic auf der USB-Schnittstelle mitschneide,> sind die Pakete alle da!
Ich muss jetzt nochmal was abklären, und zwar die Richtung:
1. Gerät -> Host
2. Host -> Gerät
Also bei welchem Transfer zeigt Dir Wireshark die Daten, aber sie kommen
trotzdem nicht an?
Sven B. schrieb:> Die Transfers sind immer Gerät -> Host. Also "In" im USB-Slang.
Also der Wireshark sagt Dir, dass die Daten am PC ankommen, und Du
suchst nach dem Problem auf Microcontroller-Seite? Obwohl die Daten am
PC ankommen?
Das musst Du mir mal erklären?
Und dann sind wir wieder bei meinem ersten Post!
Pit schrieb:> Der Host geht also her und schreibt die Daten in den Ringpuffer. Wenn Du> diese nicht rechtzeitig abholst, dann werden sie eben überschrieben und> es fehlen ein paar kBytes.> Es ist dem Host nämlich ziemlich egal, was mit den Daten passiert. Sein> Job ist es nur, sie in den Ringpuffer zu schreiben.>> Der Applikation ist es nicht egal, ob die Daten überschrieben werden> oder nicht. Und genau da kommt dann der Programmierer ins Spiel - also> Du.>> Gruß Klaus
Gruß Pit und Klaus
Ich hab das selbe Problem:
Meiner Meinung nach ist der ACM-Treiber oder irgendwas in der Gegen das
Problem.
Beispiel:
Verbinde ich einen Arduino mit einem RPi2 über USB und lese von ttyACM
gehen zeichen verloren.
Verbinde ich den Arduino (RX0/TX0) direkt mit der Pinleiste des RPi2
(RX/TX) und lese von ttyAMA geht nichts verloren.
Es geht ebenfalls nichts verloren, wenn ich das ganze über eine
UART-USB-Bridge (CP21xx) laufen lasse und von ttyUSB lese...
Ist natürlich nur (m)eine Theorie, das der ACM-Treiber das Problem
darstellt... Just sayin'.
BTW:
Um in Python von dem Seriellenport zu lesen kannst du auch das Modul
PySerial nutzen.
Klaus schrieb:> Sven B. schrieb:>> Die Transfers sind immer Gerät -> Host. Also "In" im USB-Slang.>> Also der Wireshark sagt Dir, dass die Daten am PC ankommen, und Du> suchst nach dem Problem auf Microcontroller-Seite? Obwohl die Daten am> PC ankommen?
Ich suche nicht nach dem Problem auf dem uC. Ich bin mir ziemlich
sicher, dass das Problem auf dem Host ist.
> Und dann sind wir wieder bei meinem ersten Post!
Entschuldigung, aber der Post ist meines Erachtens Quatsch. USB hat die
Möglichkeit, Pakete nochmal zu übertragen und die Übertragung zu
verlangsamen wenn die Buffer voll sind etc. und natürlich werden diese
Möglichkeiten hier auch im Hintergrund genutzt. Noch einmal, das ist ein
Bulk-Endpoint, der garantiert laut Spezifikation, dass alle Daten die
ich sende vollständig, fehlerfrei, und in der richtigen Reihenfolge auch
ankommen! Die einzige Komponente, bei der ich mir nicht komplett sicher
bin ob dasselbe gilt ist ACM. Wenn du dazu explizit weißt ob das
garantiert dass keine Daten verloren geht oder dass das eben explizit
nicht garantiert wird, bin ich dankbar; ansonsten vergiss bitte den "da
musst du dich als Anwendungsentwickler drum kümmern"-Ansatz, der ist
Unsinn, weil das an sich von den zugrundeliegenden Technologien
garantiert wird. Außer ich irre mich da eben, dann bitte ich, mich zu
erleuchten.
Kaj schrieb:> Beispiel:> Verbinde ich einen Arduino mit einem RPi2 über USB und lese von ttyACM> gehen zeichen verloren.> Verbinde ich den Arduino (RX0/TX0) direkt mit der Pinleiste des RPi2> (RX/TX) und lese von ttyAMA geht nichts verloren.> Es geht ebenfalls nichts verloren, wenn ich das ganze über eine> UART-USB-Bridge (CP21xx) laufen lasse und von ttyUSB lese...>> Ist natürlich nur (m)eine Theorie, das der ACM-Treiber das Problem> darstellt... Just sayin'.
Sehr interessant. Hast du da Details dazu wie oft das passiert, und
unter welchem Umständen oder so?
Ich stimme dir zu, ich sehe auch keine andere Fehlerquelle als den
cdc_acm-Treiber.
> BTW:> Um in Python von dem Seriellenport zu lesen kannst du auch das Modul> PySerial nutzen.
Danke, das tu ich auch, ich hab's nur rausgenommen um eine Komponente
weniger zu haben in der ein Bug sein kann.
Seufz, ich glaub' ich muss dann wohl echt mal meinen Windows-PC anwerfen
und das da versuchen.
Sven B. schrieb:> Noch einmal, das ist ein> Bulk-Endpoint, der garantiert laut Spezifikation, dass alle Daten die> ich sende vollständig, fehlerfrei, und in der richtigen Reihenfolge auch> ankommen!
Natürlich ist das so. Alles andere wäre auch völliger Schwachsinn.
Dann kann es aber nur noch an den Treibern liegen. Und das sind nun mal
nur der Kernel-Treiber (und dass es daran liegt, ist nur schwer
vorstellbar) und der User Mode Treiber, also das Teil, was Du
programmierst.
Stellt sich also die Frage: Machen die Kernel-Treiber Entwickler
irgendwas falsch (und das wohl schon seit Jahren, oder gibt es diese
Schnittstelle erst seit gestern?), oder liegt es an Deiner Software?
Sven B. schrieb:> Hah https://bugzilla.kernel.org/show_bug.cgi?id=14163> Ist aber alt ...
Das hatte ich zuvor überlesen... Offenbar kann es durchaus an den
Kernel-Jungs liegen - und das tatsächlich schon seit Jahren.
Unfassbar!
User:
'Hey, ich habe hier ein Problem mit dem USB, kann das mal einer fixen?'
Entwickler:
'Ich hab mal ne neue Version erstellt, ist das Problem jetzt weg?'
User 2:
'Naja, ich hab mal bischen rumprobiert. Bei mir klappt es.'
Entwickler:
'OK, dann ist das Problem wohl gelöst. Ich mach den Thread mal zu.'
Einfach nur geil! Was für Penner.
Sven B. schrieb:> while ( cur < size ) {> long r = read(fd, &buf[cur], size-cur);> if ( r < 0 ) {> exit(3);> }> cur += r;> }
Ich verstehe nicht ganz, warum das überhaupt funktioniert. Da du die
Schnittstelle mit O_NONBLOCK geöffnet hast, müßte read doch eigentlich,
wenn keine Daten verfügbar sind, -1 zurückliefern und errno auf EAGAIN
setzen.
Rolf M. schrieb:> Ich verstehe nicht ganz, warum das überhaupt funktioniert. Da du die> Schnittstelle mit O_NONBLOCK geöffnet hast, müßte read doch eigentlich,> wenn keine Daten verfügbar sind, -1 zurückliefern und errno auf EAGAIN> setzen.
Ich glaube es sind einfach immer Daten verfügbar.
Klaus schrieb:> Stellt sich also die Frage: Machen die Kernel-Treiber Entwickler> irgendwas falsch (und das wohl schon seit Jahren, oder gibt es diese> Schnittstelle erst seit gestern?), oder liegt es an Deiner Software?
Meine Software ist halt nur zwei Zeilen lang. Da ist das Potential für
Fehler nicht so groß.
Tatsächlich ist es halt so, dass cdc_acm wenn es einen Block liest
diesen in den tty-Buffer schreibt:
http://lxr.free-electrons.com/source/drivers/usb/class/cdc-acm.c#L405
Wenn man jetzt aber schaut, was tty_insert_flip_string konkret tut, so
ist es dies:
http://lxr.free-electrons.com/source/drivers/tty/tty_buffer.c#L324
Das kopiert also, bis der Buffer voll ist und wenn der voll ist hört es
auf und gibt die Anzahl der kopierten Bytes zurück. Es wird aber
nirgends überprüft dass das auch alle sind, die hätten kopiert werden
müssen.
Jetzt ist halt die Frage, ob das Absicht ist oder nicht?
Alle anderen Treiber machen das jedenfalls genauso. Einer gibt zumindest
eine Fehlermeldung aus ("dopping n bytes of data" blabla).
Wahrscheinlich ist das also Absicht.
Im Prinzip gibt es wohl dieses Throttling, um Bufferüberläufe zu
verhindern. Das setzt aber erst ein, wenn der Buffer nur noch 128 Byte
Platz hat. Das könnte schon zu spät sein für diesen Anwendungsfall...
Die Frage ist also im Endeffekt: Müsste das Throttling diesen Fehlerfall
mit Sicherheit verhindern?
Sven B. schrieb:> Peter II schrieb:>> das würde ich nicht sagen. Wenn du die Daten aus ttyACM0 nicht schnell>> genug aufragst, dann können sie auch verloren gehen.>> Das ist genau die Frage, die mich seit längerem beschäftigt. Ist das so?
Natürlich. Wenn Daten übertragen werden sollen, aber alle Buffer der
Protokollschichten bereits voll sind, dann MÜSSEN *ZWINGEND* Daten
weggeworfen werden.
> Ich glaube nicht: Wenn der Buffer voll ist, sollte der Host keine> weiteren Pakete mehr annehmen, und soweit ich das sehen kann ist das> auch das was passiert: Wenn man nur Daten anfragt aber nicht liest dann> werden ein paar übertragen, und danach hängt der uC in der "warte auf> `Endpoint bereit'"-Schleife fest.
So what? Dann wirft halt der µC die Daten weg... Ist doch prinzipiell
vollkommen egal, wer das tut, das Ergebnis ist in jedem Fall: die
weggeworfenen Daten kommen beim Empfänger nicht an. Aus die Maus.
Bei sinnvollen Implementierungen erfährt der Empfänger aber wenigstens
noch, dass der Fall des Datenverlustes durch buffer overrun eingetreten
ist und bekommt damit eine Möglichkeit, sich geordnet neu auf den
Datenstrom zu synchronisieren. Nützlich für den Fall, dass der Abriss
des Datenstroms nicht darauf zurückzuführen ist, dass der Empfänger
generell zu langsam ist, sondern dass er nur durch ein kurzzeitig
wirksame Ursache zeitweise vom Empfang abgehalten wurde.
c-hater schrieb:> Natürlich. Wenn Daten übertragen werden sollen, aber alle Buffer der> Protokollschichten bereits voll sind, dann MÜSSEN ZWINGEND Daten> weggeworfen werden.
Unsinn. Wenn jede Schicht prüft ob sie schreiben darf, dann geht nichts
verloren.
c-hater schrieb:> Natürlich. Wenn Daten übertragen werden sollen, aber alle Buffer der> Protokollschichten bereits voll sind, dann MÜSSEN *ZWINGEND* Daten> weggeworfen werden.
Nö, der Absender kann ja auch warten bis wieder Platz ist.
> So what? Dann wirft halt der µC die Daten weg... Ist doch prinzipiell> vollkommen egal, wer das tut, das Ergebnis ist in jedem Fall: die> weggeworfenen Daten kommen beim Empfänger nicht an. Aus die Maus.
Das ist natürlich nicht egal. Der uC kann doch als Absender viel besser
entscheiden welche Daten er wegwirft als irgendein generischer
Kerneltreiber auf dem Host. Der kann dann auch komplette Pakete
verwerfen, statt irgendwo zufällig irgendwelche Bytes rauszuschneiden.
Das dann wieder zu synchronisieren ist nämlich ziemlich schwierig ...
Ich hab mal ein bisschen rumgebastelt, es ist tatsächlich so, dass der
tty-Buffer überläuft. Es gibt einen Throttling-Mechanismus, der
eigentlich bevor dieser Fall eintritt dem Gerät signalisiert dass es
warten soll, aber der greift viel zu spät (der Buffer ist 64k groß, das
Throttling throttelt bei < 128 Byte frei, das müssten aber 16kB sein im
vorliegenden Fall oder so). Hm.
Ok, ich hab's, so tut es. Hat jetzt schon > 25 GB kopiert ohne Fehler,
vorher war immer nach ein paar MB Schluss.
Der Code ist natürlich schrecklich (ich habe keine Ahnung von
Kernel-Code), aber vielleicht kann das ja ein netter Kernel-Hacker
nochmal ordentlich machen. Ich tu' es mal in den entsprechenden Bug
Report. Ansonsten hab ich eben meinen eigenen Treiber, ist auch ok.
Peter II schrieb:> Welche Datenrate erreichst du überhaupt?
Ich brauche 11.7 MB/s, die erreiche ich auch. Das Maximum hab ich nicht
so genau ausprobiert, liegt irgendwo bei 25 MB/s rum, je nach dem.
https://lkml.org/lkml/2015/7/19/353
In dem Report wird sich wohl nix mehr tun, ich glaube die diskutieren
nicht so gern Patches im Bugtracker. Verständlicherweise.