Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

bash-problem mit "cmd1 | cmd2 > file"

11 views
Skip to first unread message

Andreas Leitgeb

unread,
Nov 24, 2011, 11:17:55 AM11/24/11
to
Gleich vorweg, das Problem ist nich unter Linux sondern Solaris 10
aufgetreten, aber eben nur mit der bash, nicht mit der ksh
Auf die Chance hin, dass bash, und nicht solaris der verursacher
ist, frag ich mal hier.

Das Problem ist, dass eine pipeline und ein weiteres Kommando
cmd1 | cmd2 > file; cmd3 < file
gestartet werden, und beim Start von cmd3 das "file" manchmal(*)
nicht *vorhanden* ist, also eben nicht einmal als leeres file!
*: Wär ja langweilig, wenn's nicht auch noch ein Heisenbug wäre.

Diese Kommandos wurden für ca 500 von ca 20000 Dateien eines
Verzeichnisses aufgerufen (for i in abc*; do ... ; rm file; done),
und funktionierten für die ersten 200 davon tadellos, ab dann kam
es bei ca jeder dritten zu dem Fehler, dass für cmd3 das file fehlte.
Die Anzahl an anfangs erfolgreichen Dateien variierte geringfügig
(+-50). Das schiefgehen für eine datei hatte scheinbar nichts mit
dem Inhalt der jeweiligen datei zu tun.

Nach der Änderung auf
cmd1 | cmd2 | cmd3
lief alles bestens, ebenso, wenn ich die ursprüngliche Version
unter ksh laufen liess.
D.h.: Es geht nicht um die lösung meines Problems, sondern um
die identifizierung eines bash-bugs(?) und ob er schon bekannt/
gefixt/... oder eben neu ist.
echo $BASH_VERSION sagt: 3.00.16(1)-release

Google liefert nach den Stichworten die ich probiert habe (*)
ca 2 millionen treffer, davon auf den ersten paar seiten nichts
auch nur annähernd relevantes.
*: z.B.: bash bug redirection "no file"

Andreas Leitgeb

unread,
Nov 24, 2011, 11:23:16 AM11/24/11
to
Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:
> Das Problem ist, dass eine pipeline und ein weiteres Kommando
> cmd1 | cmd2 > file; cmd3 < file
> gestartet werden, und beim Start von cmd3 das "file" manchmal(*)
> nicht *vorhanden* ist, ...
...
> Nach der Änderung auf
> cmd1 | cmd2 | cmd3
> lief alles bestens, ...

Nachsatz: auch bei
cmd1 > file ; cmd2 < file | cmd3
trat das symptom *nicht* auf.

Und weiters: es war noch reichlich Platz auf der Partition.

jakob kollmann

unread,
Nov 24, 2011, 1:42:17 PM11/24/11
to
On 11/24/2011 5:23 PM, Andreas Leitgeb wrote:
> Andreas Leitgeb<a...@gamma.logic.tuwien.ac.at> wrote:
>> Das Problem ist, dass eine pipeline und ein weiteres Kommando
>> cmd1 | cmd2> file; cmd3< file
>> gestartet werden, und beim Start von cmd3 das "file" manchmal(*)
>> nicht *vorhanden* ist, ...

\> uname -a
SunOS xxxxxxx 5.10 Generic_120011-14 sun4u sparc SUNW,Sun-Fire-V240
\> echo $BASH_VERSION
3.00.16(1)-release

\> for i in $(find /usr -type f); do md5_sunOS $i|cut -d " " -f 1 >file
| sort <file; done

läuft bei mir ohne Probleme. Wie groß sind deine Files ca.?

lg. jakob

Andreas Leitgeb

unread,
Nov 25, 2011, 1:15:34 PM11/25/11
to
jakob kollmann <jakob.k...@filofant.org> wrote:
> On 11/24/2011 5:23 PM, Andreas Leitgeb wrote:
>> Andreas Leitgeb<a...@gamma.logic.tuwien.ac.at> wrote:
>>> Das Problem ist, dass eine pipeline und ein weiteres Kommando
>>> cmd1 | cmd2> file; cmd3< file
>>> gestartet werden, und beim Start von cmd3 das "file" manchmal(*)
>>> nicht *vorhanden* ist, ...
> \> for i in $(find /usr -type f); do md5_sunOS $i|cut -d " " -f 1 >file
> | sort <file; done
> läuft bei mir ohne Probleme. Wie groß sind deine Files ca.?

Vielen Dank für den Test.

Ich habe den Fehler mittlerweile auf einer anderen Maschine
und mit gewissen Vereinfachungen reproduzieren können.

Die folgende Kommandozeile führt (in einem leeren Verzeichnis)
zum Fehler, wenngleich man etwas Geduld braucht - jede for-
Iteration braucht hier auf einer älteren lahmen Ente etwa 8
Sekunden, und nach ca 40 (+-10) Iterationen beginnen hier
die Fehler aufzutreten:

for i in {1..500}; do
echo $i;
yes foo | head -100 > foo;
while read f; do
false | cat | cat | cat | cat | cat | cat;
done < foo;
rm foo;
done | tee out

Das "| tee out" am Ende scheint jedenfalls auch relevant zu sein!

Interessant ist dabei, dass die Komplexität in der while-Schleife
eine Auswirkung hat, ob das andere Kommando die Datei anlegt und
füllt: Reduziert man etwa die 6 "cat"s auf 4, taucht der Fehler im
Durchschnitt erst um einiges später auf.

Wenn er erst mal aufgetreten ist, taucht er dann gleich deutlich öfter
auf. Nach einem Abbruch und (selbst schnellem) wieder-Start dieser Zeile
muss man aber wieder aufs Neue warten...

PS: und weil das Beispiel so sinnlos scheint: das "yes | head" war
ursprünglich "tar tzf $i | grep ... > file", und die while-Schleife
hat dann für jede Zeile (read f) der Datei "file" das Kommando
tar xzOf $i $f | ... | grep dieses | grep -v jenes
ausgeführt. Das "rm" war damals noch nicht drin, und plötzlich
gab der tar Fehler, dass das Archiv-file die gewünschte Datei
nicht enthielt - es wurde nämlich das vom *vor*letzten "tar tzf"
geschriebene file für die aktuelle while-Schleife "wiederverwendet".

Message has been deleted

Andreas Leitgeb

unread,
Nov 26, 2011, 9:01:27 AM11/26/11
to
David Wührer <d...@gmx.at> wrote:
> Andreas Leitgeb wrote:
>> Die folgende Kommandozeile führt (in einem leeren Verzeichnis)
>> zum Fehler, wenngleich man etwas Geduld braucht - jede for-
>> Iteration braucht hier auf einer älteren lahmen Ente etwa 8
>> Sekunden, und nach ca 40 (+-10) Iterationen beginnen hier
>> die Fehler aufzutreten:
>>
>> for i in {1..500}; do
>> echo $i;
>> yes foo | head -100 > foo;
>> while read f; do
>> false | cat | cat | cat | cat | cat | cat;
>> done < foo;
>> rm foo;
>> done | tee out
>>
>> Das "| tee out" am Ende scheint jedenfalls auch relevant zu sein!
>
> Klingt wie eine Race-Condition zwischen dem Anlegen und dem Lesen der Datei.

Das, oder ein nicht-gefehlermeldeter ressourcen-mangel
beim Öffnen der ausgabedatei...

> Als ob das Betriebssystem vor lauter Pipes legen nicht mehr dazu kommt, die
> Dateien zu verknüpfen.
> Und ich denke, der Page Cache wird auch irgendwann voll sein.
> Vielleicht hilft ein strategisch plaziertes sync.

Da kann ich dir jetzt nicht so ganz folgen. Ehrlich gesagt klingt es für
mich, als würdest du hier einfach nur irgendwelche Begriffe zusammenwürfeln,
die du aufgeschnappt hast. Oder mein Komik-detektor braucht eine Rekalibrierung.

jakob kollmann

unread,
Nov 28, 2011, 9:21:25 AM11/28/11
to
On 11/25/2011 7:15 PM, Andreas Leitgeb wrote:
>
> Die folgende Kommandozeile führt (in einem leeren Verzeichnis)
> zum Fehler, wenngleich man etwas Geduld braucht - jede for-
> Iteration braucht hier auf einer älteren lahmen Ente etwa 8
> Sekunden, und nach ca 40 (+-10) Iterationen beginnen hier
> die Fehler aufzutreten:
>

Schaut bei mir so ähnlich aus (Iterationen dauern etwa 3s):

43
44
foo: No such file or directory
45
bash: foo: No such file or directory
46
bash: foo: No such file or directory
47
48
bash: foo: Interrupted system call
49

Wär es möglich, dass man da in irgendein ulimit (open files oä)
läuft, wenn die files/pipes nicht schnell genug weggeräumt werden?

lg. jakob
Message has been deleted

Andreas Leitgeb

unread,
Nov 28, 2011, 3:43:01 PM11/28/11
to
David Wührer <d...@gmx.at> wrote:
> Andreas Leitgeb wrote:
>> Das, oder ein nicht-gefehlermeldeter ressourcen-mangel
>> beim Öffnen der ausgabedatei...
> Es klingt so, als würde versucht, die Datei zu öffnen, bevor sie überhaupt
> angelegt wurde.

Ja, damit hast du - weiteren experimenten meinserseits zufolge - Recht.

Ich habe es (in leicht variierter Version: sobald der open zum lesen
schiefgeht, bricht es nun die for-schleife ab) nocheinmal laufen lassen,
und in einem anderen Fenster einen truss (das unix-pendant zu linux's
strace) auf die shell und alle ihre Kinder gemacht und | grep open.*foo
siehe da:

...
10023: open64("foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
12752: open64("foo", O_RDONLY) = 4
14154: open64("foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
12752: open64("foo", O_RDONLY) = 4
14160: open64("foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
12752: open64("foo", O_RDONLY) = 4
12752: open64("foo", O_RDONLY) Err#2 ENOENT
14166: open64("foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4

Zum einen ist der open, der die datei anlegt aus einem anderen
prozess, und dort kommt das Datei-anlegen dann zu spaet, und die
naechst-aeussere shell wartet nicht korrekt, bis die subshell
fertig ist, bevor sie das nächste Kommando startet.

> Dass mehr Pipes bedeuten, dass die Fehler schneller auftreten, könnte
> vielleicht etwas damit zu tun haben, dass das Umleiten der Datenströme, also
> das Verbinden und Lösen von Dateideskriptoren miteinander, verhindert, dass
> neue Dateideskriptoren für eigentliche Dateien schnell genug angelegt werden
> können. Deshalb existieren sie dann noch nicht, bevor sie geöffnet werden.

Was ich an diesem Absatz nicht verstehe ist, dass es mir letztlich (fast) egal
ist, wie lange der nun für das mist-wegraeumen und neue datei-anlegen wirklich
braucht, solange die übergeordnete shell einfach darauf *wartet*, und genau
das scheint sie aber nicht so ganz verlaesslich zu tun.

> Die Daten müssen nur im Page Cache existieren, um gelesen werden zu können.

Da nun laut truss geklärt ist, dass die open()s tatsächlich zeitlich
in falscher Reihenfolge kommen, brauch ich nun zum glück nicht auf so
schwere Geschütze als Erklärung zurückgreifen.

> Meine Überlegung war, dass es vielleicht hilft, wenn man eine
> Synchronisierung des Caches erzwingt, mit dem Befehl sync, nachdem eine
> Datei geschrieben wurde, und bevor sie erneut zum Lesen geöffnet wird.

Ja, aber es würde wahrscheinlich in genau dem gleichen Maße helfen,
wie ein sleep 1 ;-)

> Eine andere Idee wäre, diese Dateien in einer RAM-Disk zu erzeugen.

Diesen Vorschlag habe ich mir zu Herzen genommen: die weiteren Versuche waren
dann in einem Verzeichnis unter /tmp (was unter solaris üblicherweise eine
ramdisk ist). Hat aber nicht wirklich was am Ergebnis geaendert.

PS: Danke, und sorry, dass ich deine erste Antwort offenbar falsch verstanden
habe.

Andreas Leitgeb

unread,
Nov 29, 2011, 5:25:12 AM11/29/11
to
Ich habe einige der prozesse mit truss (siehe Antwort auf David's 2.
Antwort) und auch mit lsof betrachtet, aber ein "fd"-leak konnte ich
dabei nicht erkennen.

Meine Vermutung ist, dass die bash bei "waitid(P_ALL,..." aus dem
tritt kommt, und sie das Fertigwerden eines ganz anderen Childs
mit dem Fertigwerden des relevanten Childs "verwechselt", auf das
sie eigentlich warten hätte sollen.

Bernd Petrovitsch

unread,
Nov 29, 2011, 7:06:23 AM11/29/11
to
On Mon, 28 Nov 2011 15:25:28 +0100, David Wührer wrote:
> Andreas Leitgeb wrote:
>> Das, oder ein nicht-gefehlermeldeter ressourcen-mangel
>> beim Öffnen der ausgabedatei...
>
> Es klingt so, als würde versucht, die Datei zu öffnen, bevor sie überhaupt
> angelegt wurde.
>
> Dass mehr Pipes bedeuten, dass die Fehler schneller auftreten, könnte
> vielleicht etwas damit zu tun haben, dass das Umleiten der Datenströme, also
> das Verbinden und Lösen von Dateideskriptoren miteinander, verhindert, dass
> neue Dateideskriptoren für eigentliche Dateien schnell genug angelegt werden
> können. Deshalb existieren sie dann noch nicht, bevor sie geöffnet werden.

System-Calls sind - soweit es den User-Space angeht - atomar (wenn wir mal
einen diesbezüglich bugfreien Kernel unterstellen).

> Die Daten müssen nur im Page Cache existieren, um gelesen werden zu können.

Aber von jedem User-Space-Prozeß.

> Dieser wird regelmäßig mit dem Festspeicher selbst syncronisiert werden, um
> Datenverluste zB bei Stromausfall zu vermeiden. Entweder das passiert in
> Intervallen, oder wenn der Page Cache voll ist und Seiten daraus anderweitig
> benötigt werden.
> Wenn das passiert, werden Ein/Ausgabeoperationen auf Dateien verzögert
> werden, weil ja das Schreiben auf die Platte um einiges länger dauert als in
> den Cache, und bis dahin auch einiges an Dateien zusamengekommen sein wird.

Uninteressant - der Page Cache ist nur als Speedup da damit eben möglichst
wenig verzögert wird..

> Auch wenn immer wieder die selbe Datei überschrieben wird, werden die
> Dateien nicht an der selben Stelle des Festspeichers geschrieben werden. Der
> Page Cache wird das ebenso abbilden, wenn neue erzeugt werden, bevor alte
> gelöscht werden.

Mag alles sein, aber der VFS und das Filesystem müssen das korrekt nach oben
hinkriegen.

> Meine Überlegung war, dass es vielleicht hilft, wenn man eine
> Synchronisierung des Caches erzwingt, mit dem Befehl sync, nachdem eine
> Datei geschrieben wurde, und bevor sie erneut zum Lesen geöffnet wird.

"sync" erzwingt bestenfalls, daß der Page Cache u.ä. nach unten gedrückt
wird.
Ob bzw. wann die Daten physikalisch auf der Festplatte landen, ist eine
ganz andere Frage - Festplatten haben heute alle einen eigenen Cache.

> Eine andere Idee wäre, diese Dateien in einer RAM-Disk zu erzeugen.

Der gesamte User-Space sieht das, was im VFS "oben" ist. Ob drunter
eine Festplatte ist oder RAMdisk oder sonstwas, sollte egal sein. Ebenso
wo und wie drunter Files auf Festplatten (die eigentlich Block Devices
sind) abgelegt werden.

Was macht
cmd1 | cmd2 > file; cmd3 < file
?

"cmd3" wird erst gestartet, wenn "cmd1 | cmd2" fertig ist. "file" wird
angelegt, bevor "cmd2" gestartet wird (weil "cmd2" den umgeleiteten
stdout mitbekommt) und existiert damit bevor "cmd2" gestartet wurde.
Nachdem das nur manchmal pasiert, stinkt es nach Race Condition (und
damit ein Bug). *Wenn* es eine Race Condition ist, dann könnte ein
Ramdisk das kaschieren, aber sicher nicht lösen.

Wenn obiges gelegentlich meint, daß "file" (bei "cmd3"!) nicht
existiert, fallen mir nur 2 einfache Ursachen ein:
- Bash-Bug (und der wird mit dem Rest des Threads immer wahrscheinlicher,
v.a. weil es mit anderen Shells nicht passiert. Deshalb wird es kaum
im Kernel liegen).
- irgendwer anderer (Daemon, Cron-Script, ....) löscht
regelmäßig/laufend/permanent "file" weg und gelegentlich im richtigen
bzw. falschen Moment.
Bernd
--
- Wie erkennt man IYO die offensichtlich ungeeigneten, hinter denen sich
nicht das Genie verbirgt?
- Wie erkennt man das Offensichtliche?
Martina Diel und Volker Birk

Andreas Leitgeb

unread,
Nov 29, 2011, 11:15:49 AM11/29/11
to
Bernd Petrovitsch <be...@tuxoid.at> wrote:
> Was macht
> cmd1 | cmd2 > file; cmd3 < file
> ?
> "cmd3" wird erst gestartet, wenn "cmd1 | cmd2" fertig ist.

Und genau dieses Axiom wurde in der Praxis gebrochen.

> "file" wird angelegt, bevor "cmd2" gestartet wird (weil "cmd2" den
> umgeleiteten stdout mitbekommt)

Das schon, aber das nicht zwingend von demselben prozess, der danach
cmd3 startet. Für die pipe "cmd1 | cmd2" werden unterprozesse gestartet,
von denen dann der zweite das file anlegt und einen exec auf cmd2 macht.
Die äussere shell sollte aber eigentlich darauf warten, bis alles rund
um cmd1 und cmd2 fertig ist.

> Wenn obiges gelegentlich meint, daß "file" (bei "cmd3"!) nicht
> existiert, fallen mir nur 2 einfache Ursachen ein:
> - Bash-Bug (und der wird mit dem Rest des Threads immer wahrscheinlicher,
> v.a. weil es mit anderen Shells nicht passiert. Deshalb wird es kaum
> im Kernel liegen).

Ist auch meine Vermutung. Aber die Schlussfolgerung ist zumindest nicht
wasserdicht: ksh könnte zufällig einen anderen syscall verwenden, der
halt einen bestimmten kernel-bug nicht streift.

> - irgendwer anderer (Daemon, Cron-Script, ....) löscht
> regelmäßig/laufend/permanent "file" weg und gelegentlich im richtigen
> bzw. falschen Moment.

Das schliess ich für diesen Fall mal kategorisch aus :-)

Message has been deleted

Bernd Petrovitsch

unread,
Nov 30, 2011, 6:33:51 AM11/30/11
to
On Tue, 29 Nov 2011 16:15:49 +0000, Andreas Leitgeb wrote:
> Bernd Petrovitsch <be...@tuxoid.at> wrote:
>> Was macht
>> cmd1 | cmd2 > file; cmd3 < file
>> ?
>> "cmd3" wird erst gestartet, wenn "cmd1 | cmd2" fertig ist.
>
> Und genau dieses Axiom wurde in der Praxis gebrochen.
>
>> "file" wird angelegt, bevor "cmd2" gestartet wird (weil "cmd2" den
>> umgeleiteten stdout mitbekommt)
>
> Das schon, aber das nicht zwingend von demselben prozess, der danach
> cmd3 startet. Für die pipe "cmd1 | cmd2" werden unterprozesse gestartet,

Eh nicht. Das ist ja auch unwesentlich, welche PID "file" erzeugt.
Ich unterstelle mal ein normales Filesystem ....

> von denen dann der zweite das file anlegt und einen exec auf cmd2 macht.
> Die äussere shell sollte aber eigentlich darauf warten, bis alles rund
> um cmd1 und cmd2 fertig ist.

Ja, sollte sie. Tut sie wohl nicht (ganz fehlerfrei).

>> Wenn obiges gelegentlich meint, daß "file" (bei "cmd3"!) nicht
>> existiert, fallen mir nur 2 einfache Ursachen ein:
>> - Bash-Bug (und der wird mit dem Rest des Threads immer wahrscheinlicher,
>> v.a. weil es mit anderen Shells nicht passiert. Deshalb wird es kaum
>> im Kernel liegen).
>
> Ist auch meine Vermutung. Aber die Schlussfolgerung ist zumindest nicht
> wasserdicht: ksh könnte zufällig einen anderen syscall verwenden, der
> halt einen bestimmten kernel-bug nicht streift.

Ich hab zum einen einen bugfreien Kernel unterstellt;-)

Zum anderen gibt es nicht so dermaßen viele verschiedenen Sys-Calls und
manche unterscheiden sich nur darin, daß die mehr oder weniger Parameter
haben (und damit mehr bzw. weniger Information kriegen bzw. liefern).
Im Kernel endet das idR in derselben Funktion, wo halt sinnvolle
Defaults verwendet werden.
Und die anderen Ergebnisse mit "jedes x.te mal gab es den Fehler" stinkt
gewaltig nach Race Conditions ....

Hmm, die Testruns strace(n) und dann die GB an Output anschauen?!
Da ist es vermutlich zielführender, erstmal im bash-Source nach zu lesen
und vllt. dort was einzubauen.

>> - irgendwer anderer (Daemon, Cron-Script, ....) löscht
>> regelmäßig/laufend/permanent "file" weg und gelegentlich im richtigen
>> bzw. falschen Moment.
>
> Das schliess ich für diesen Fall mal kategorisch aus :-)

Ja, beim Bug hunting wird man da wohl im eiegne Directory ausporbieren.

Bernd Petrovitsch

unread,
Nov 30, 2011, 6:52:34 AM11/30/11
to
On Tue, 29 Nov 2011 17:20:35 +0100, David Wührer wrote:
> Bernd Petrovitsch wrote:
>
>> System-Calls sind - soweit es den User-Space angeht - atomar (wenn wir mal
>> einen diesbezüglich bugfreien Kernel unterstellen).
>
> Genau. Und die Shell startet den nächsten Prozess hinter dem Strichpunkt
> erst, wenn sich der Prozess davor beendet hat, was er nicht tut, bevor sich
> nicht dessen letztes close() zurückgemeldet hat.
>
> Das bedeutet, dass die Datei damit angelegt sein sollte und andere darauf
> schreiben können, soweit es das Betriebssystem betrifft.

... und lesen können.
s/Betriebssystem/Kernel/ (und wenn es nur für die Klarheit ist)

> Nach dem close() auf die Datei wird ein unlink() aufgerufen, aber in einem
> anderen Prozess. Die Shell kümmert sich um diese Reihenfolge. Das

Wer soll da unlink() aufrufen und v.a. warum?
"file" sollte da überbleiben.

Alles andere wäre unerwartet und buggy.

[ ... Konkunktive entsorgt - Spekulationen bringen wenig. ...]

[ ... Use-after-remove entsorgt - da wird nichts gelöscht. ... ]

>> "sync" erzwingt bestenfalls, daß der Page Cache u.ä. nach unten gedrückt
>> wird.
>
> Und alle Lese- und Schreibzugriffe auf den Festspeicher aus dem Userspace
> bis dahin blockieren.

Für den Prozeß, der den sync(2)-Sys-Call aufruft, gilt das. Für den Rest
würde ich das bezweiflen (und ich seh auch keinen besonderen Sinn darin,
dieses zu tun).

>> Ob bzw. wann die Daten physikalisch auf der Festplatte landen, ist eine
>> ganz andere Frage - Festplatten haben heute alle einen eigenen Cache.
>
> Um den muss und kann sich aber das Betriebssystem nicht kümmern.
> Aus der Sicht des Betriebssystems ist der festplatteninterne Cache die
> Festplatte selbst.

Im Moment kümmern sich die Treiber nicht rum, weil es mWn nichts
standardisiertes in der SCSI- oder ATAPI-Welt gibt.
Rein strategisch seh ich keinen Grund, warum das ein Treiber nicht tun
sollte.

> Der Festspeicher muss nicht einmal eine Festplatte sein, sondern kann auch
> direkt eine SSD sein.

Je nachdem. Festplatte mit Cache ist da ja das Wortst-Case-Bsp gewesen.

>> Der gesamte User-Space sieht das, was im VFS "oben" ist. Ob drunter
>> eine Festplatte ist oder RAMdisk oder sonstwas, sollte egal sein. Ebenso
>> wo und wie drunter Files auf Festplatten (die eigentlich Block Devices
>> sind) abgelegt werden.
>
> Aus Sicht des Userspace sind diese gleich.
> Aber eine RAM-Disk braucht nicht im Page Cache gespiegelt zu werden.

Ein RAM-Disk kann auch nur im Page Cache leben - ist die Frage, wie die
Ramdisk im Kernel implementiert ist.

> Falls die Dateien klein genug sind, dass sich die gesamte Schleife im Cache
> abspielt, macht es keinen Unterschied, aber falls der Fehler wirklich in dem
> Moment aufreten sollte, in dem auf den Festspeicher gewartet wird, würde das
> damit wegfallen.
>
> Tut es aber nicht. Daran liegt es also nicht.

Das ganze Festspeicher-oder-nicht-zeugs ist irrelevant und verwirrt nur. Das
wird (frühestens) erst interssant, wenn der Fehler bei ext4 auftritt und bei
bei einem anderen Filesystem nicht.
Und dann sind wir erst beim Filesystem und noch immer nicht am Blockdevice
drunter.

MbMn vermischt Du dauernd zuviele Schichten und vergißt alles was, dazwischen
ist.
*) VFS - Filesystem - Block Device - Hardware
*) Page Cache - Register der CPU
Ich würd' eher mal die Schicht suchen, wo was schief geht.

>> Wenn obiges gelegentlich meint, daß "file" (bei "cmd3"!) nicht
>> existiert, fallen mir nur 2 einfache Ursachen ein:
>> - Bash-Bug (und der wird mit dem Rest des Threads immer wahrscheinlicher,
>> v.a. weil es mit anderen Shells nicht passiert. Deshalb wird es kaum
>> im Kernel liegen).
> Vielleicht macht die Korn Shell nach jedem Schließen einer zum Schreiben
> geöffneten Datei ein fsync(), und die bash nicht, weil sie sich dafür auf
> das Betriebssystem verlässt und es unter Linux bremsen würde?

Schau halt mal nach, ob das die ksh macht .....

Allein die Beobachtung, daß mit der ksh geht und der bash nicht, läßt mich
auf "Problem in der bash" tippen.
Allenfalls noch andere Shells testen (zsh, csh, tcsh, dash, busybox ash
fallen mir da auf die Schnelle ein).
Message has been deleted

Bernd Petrovitsch

unread,
Dec 2, 2011, 4:07:18 AM12/2/11
to
On Thu, 01 Dec 2011 12:47:14 +0100, David Wührer wrote:
> Bernd Petrovitsch wrote:
>> On Tue, 29 Nov 2011 17:20:35 +0100, David Wührer wrote:
>
>> Wer soll da unlink() aufrufen und v.a. warum?
>
> rm, um die Datei zu löschen.

Wo wird da "rm" aufgerufen?

Ich bin bei
cmd1 | cmd2 > file; cmd3 < file
davon ausgegangen, daß keines davon "rm" ist.

>> [ ... Use-after-remove entsorgt - da wird nichts gelöscht. ... ]
>
> Warum existiert die Datei dann nicht?

Gute Frage. Daher kommt das mit dem "strace -f -F"n der (top level) bash
und Output anschauen .....

>> Für den Prozeß, der den sync(2)-Sys-Call aufruft, gilt das. Für den Rest
>> würde ich das bezweiflen (und ich seh auch keinen besonderen Sinn darin,
>> dieses zu tun).
>
> Weil es nur einen Schreib-Lese-Arm gibt, und seitenweise geschrieben wird.

Du hast eine erschreckende komische Vorstellung von Hardware.

>> Festplatte mit Cache ist da ja das Wortst-Case-Bsp gewesen.
>
> Der Cache der Festplatte ist dafür irrelevant.

?? Zuerts versuchst Du, Cache-Kohärenz-Probleme zu konstruieren und dann
wird der n+1. Cache ignoriert?

>> Ein RAM-Disk kann auch nur im Page Cache leben - ist die Frage, wie die
>> Ramdisk im Kernel implementiert ist.
>
> Ja. Entscheidend ist, dass sie nur im RAM existiert.

Ja, aber die existiert unter dem VFS-Layer und der gesamte User-Space sieht
über den einzigen VFS dasselbe von drunter existierenden Diskspace.

[....]
>> MbMn vermischt Du dauernd zuviele Schichten und vergißt alles was,
>> dazwischen ist.
>> *) VFS - Filesystem - Block Device - Hardware
>> *) Page Cache - Register der CPU
>> Ich würd' eher mal die Schicht suchen, wo was schief geht.
>
> Es scheint eine Race Condition zu sein.

Die kann auch nur in der bash beim Subprozeßhandling sein.

> Es ist also das Zusammenspiel verschiedener Dinge, die dazu führen,
> nicht ein Fehler in einer bestimmten Schicht.

Occams Razor läßt grüßen - anstatt Kernel Bugs zu konstruieren und wild
quer durch mehrere Schichten potentielle Probleme zu konstruieren, würde
ich in der bash mal den Bug/Race Condition suchen, die die dort die Pipes
u.ä. handlen.

>> Schau halt mal nach, ob das die ksh macht .....
>
> So wie das aussieht, verlässt sich die ksh für überhaupt nichts aufs
> Betriebssystem. Sie bringt sogar ihre eigene stdio-Lib mit. Und wenn möglich

Definiere "Betriebssystem".

Die ksh verläßt sich auf den Kernel - in Ermangelung von Alternativen.

*Falls* es an der stdio-Lib hängt (was ich genauso stark bezweifle wie einen
Kernel-Bug), dann hätte man einen libc-Bug gefunden (ich nehm mal an,
GNU-libc) und die wird ja auch nicht soooo selten verwendet.

Abgesehen davon hat die Existenz vs Nicht-Existenz eines Files nichts mit
der Implementierung einer stdio-Lib zu tun - die verwendet unten ja auch
nur open(2) und entweder geht das gut oder nicht.
Laß das auch weg, das verwirrt auch nur und bringt nichts.

[ ... Implementationdetails entsorgt ...]

Ah ja, das Rad neu erfunden und parallel implementiert ....

Andreas Leitgeb

unread,
Dec 2, 2011, 5:01:19 AM12/2/11
to
Bernd Petrovitsch <be...@tuxoid.at> wrote:
>>> Wer soll da unlink() aufrufen und v.a. warum?
>> rm, um die Datei zu löschen.
> Wo wird da "rm" aufgerufen?
> Ich bin bei
> cmd1 | cmd2 > file; cmd3 < file
> davon ausgegangen, daß keines davon "rm" ist.

Der Diskussionsfaden ist seit dem erst-Post weitergegangen.
Ich habe dann ein konkretes test-script gepostet, das das schema
(mit sinnlosen aber konkreten kommandos statt cmd#) in einer schleife
aufruft. Natürlich musste ich da das file am schleifen-ende löschen,
sonst wäre bei der naechsten iteration das file ja sowieso schon da.

>> Es ist also das Zusammenspiel verschiedener Dinge, die dazu führen,
>> nicht ein Fehler in einer bestimmten Schicht.
> Occams Razor läßt grüßen - anstatt Kernel Bugs zu konstruieren und wild
> quer durch mehrere Schichten potentielle Probleme zu konstruieren, würde
> ich in der bash mal den Bug/Race Condition suchen, die die dort die Pipes
> u.ä. handlen.

+1

Andreas Leitgeb

unread,
Dec 2, 2011, 5:13:19 AM12/2/11
to
Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:
> Die folgende Kommandozeile führt (in einem leeren Verzeichnis)
> zum Fehler, wenngleich man etwas Geduld braucht - jede for-
> Iteration braucht hier auf einer älteren lahmen Ente etwa 8
> Sekunden, und nach ca 40 (+-10) Iterationen beginnen hier
> die Fehler aufzutreten:
>
> for i in {1..500}; do
> echo $i;
> yes foo | head -100 > foo;
> while read f; do
> false | cat | cat | cat | cat | cat | cat;
> done < foo;
> rm foo;
> done | tee out
> Das "| tee out" am Ende scheint jedenfalls auch relevant zu sein!

Ein "| cat" anstelle des "| tee out" tut's übrigens auch, aber ohne
eine pipe nach der aeusseren schleife tritt das problem nicht auf.

Bernd: das hier ist das konkrete Beispiel (mit "rm").

--
Und nein, das hat nichts mit dem "Doktor, es tut weh, wenn ich da
druecke" - "dann drueck halt eben nicht da" zu tun. An dieser
Stelle druecken sollte einfach nicht weh tun.

Andreas Leitgeb

unread,
Dec 2, 2011, 5:24:11 AM12/2/11
to
Bernd Petrovitsch <be...@tuxoid.at> wrote:
>>> "file" wird angelegt, bevor "cmd2" gestartet wird (weil "cmd2" den
>>> umgeleiteten stdout mitbekommt)
>> Das schon, aber das nicht zwingend von demselben prozess, der danach
>> cmd3 startet. Für die pipe "cmd1 | cmd2" werden unterprozesse gestartet,
> Eh nicht. Das ist ja auch unwesentlich, welche PID "file" erzeugt.
> Ich unterstelle mal ein normales Filesystem ....

Wäre es derselbe Prozess gewesen, der file anlegt und gleich darauf
nicht findet, dann hätte man den Bug wohl wirklich im Kernel suchen
müssen. War aber eben nicht so. Das meinte ich.

Bernd Petrovitsch

unread,
Dec 2, 2011, 10:16:22 AM12/2/11
to
On Fri, 02 Dec 2011 10:01:19 +0000, Andreas Leitgeb wrote:
> Bernd Petrovitsch <be...@tuxoid.at> wrote:
>>>> Wer soll da unlink() aufrufen und v.a. warum?
>>> rm, um die Datei zu löschen.
>> Wo wird da "rm" aufgerufen?
>> Ich bin bei
>> cmd1 | cmd2 > file; cmd3 < file
>> davon ausgegangen, daß keines davon "rm" ist.
>
> Der Diskussionsfaden ist seit dem erst-Post weitergegangen.
> Ich habe dann ein konkretes test-script gepostet, das das schema
> (mit sinnlosen aber konkreten kommandos statt cmd#) in einer schleife
> aufruft. Natürlich musste ich da das file am schleifen-ende löschen,
> sonst wäre bei der naechsten iteration das file ja sowieso schon da.

Ja, klar, wenn man den Testcase -zig Mal in eienr Schleife aufruft,
dann muß man vorher und/oder nachher aufräumen.
Aber der Kern des Problems war obige Zeile (bzw. ähnliche in den
Testscripts) und da sehe ich nicht, wie "file" gelöscht soll.

Nachdem "cmd3" "file" nicht findet (und wir die trivialen Ursachen wie
"fehlende Permissions", "Pfad existeirt nicht", "Disk full", "kein
Inode mehr frei" ausschließen), wird es wohl noch nicht angelegt sein.
Das müßte man eigentlich in einem "strace -f -F"-Output sehen/finden
können, wo die relevanten open(), fork(), wait*() und execve()s
sind .....

Bernd Petrovitsch

unread,
Dec 2, 2011, 10:51:38 AM12/2/11
to
On Fri, 02 Dec 2011 10:13:19 +0000, Andreas Leitgeb wrote:
> Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:
>> Die folgende Kommandozeile führt (in einem leeren Verzeichnis)
>> zum Fehler, wenngleich man etwas Geduld braucht - jede for-
>> Iteration braucht hier auf einer älteren lahmen Ente etwa 8
>> Sekunden, und nach ca 40 (+-10) Iterationen beginnen hier
>> die Fehler aufzutreten:
>>
>> for i in {1..500}; do
>> echo $i;
>> yes foo | head -100 > foo;
>> while read f; do
>> false | cat | cat | cat | cat | cat | cat;
>> done < foo;
>> rm foo;
>> done | tee out
>> Das "| tee out" am Ende scheint jedenfalls auch relevant zu sein!
>
> Ein "| cat" anstelle des "| tee out" tut's übrigens auch, aber ohne
> eine pipe nach der aeusseren schleife tritt das problem nicht auf.
>
> Bernd: das hier ist das konkrete Beispiel (mit "rm").

Hmm, obiges rennt bei mir fehlerfrei durch - auch öfter wie 500 Mal.
Naja, AMD Phenom(tm) II X4 810 Processor .....

Andreas Leitgeb

unread,
Dec 4, 2011, 5:14:25 PM12/4/11
to
Bernd Petrovitsch <be...@tuxoid.at> wrote:
> On Fri, 02 Dec 2011 10:13:19 +0000, Andreas Leitgeb wrote:
>> Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:
>>> Die folgende Kommandozeile führt (in einem leeren Verzeichnis)
>>> zum Fehler, wenngleich man etwas Geduld braucht - jede for-
>>> Iteration braucht hier auf einer älteren lahmen Ente etwa 8
>>> Sekunden, und nach ca 40 (+-10) Iterationen beginnen hier
>>> die Fehler aufzutreten:
>>> for i in {1..500}; do
>>> echo $i;
>>> yes foo | head -100 > foo;
>>> while read f; do
>>> false | cat | cat | cat | cat | cat | cat;
>>> done < foo;
>>> rm foo;
>>> done | tee out
>>> Das "| tee out" am Ende scheint jedenfalls auch relevant zu sein!
>> Ein "| cat" anstelle des "| tee out" tut's übrigens auch, aber ohne
>> eine pipe nach der aeusseren schleife tritt das problem nicht auf.
> Hmm, obiges rennt bei mir fehlerfrei durch - auch öfter wie 500 Mal.
> Naja, AMD Phenom(tm) II X4 810 Processor .....

Ja, unter linux (mit 4er bash) konnte ich es auch nicht reproduzieren.
Der Fehler trat auf Solaris 10 mit einer 3er bash auf.

Werd wohl beizeiten mal eine uralte linux live cd probieren müssen,
um zu sehen, ob es mit einer entsprechend alten bash auch unter
linux schiefging.

jakob kollmann

unread,
Dec 5, 2011, 7:13:45 AM12/5/11
to
On 12/4/2011 11:14 PM, Andreas Leitgeb wrote:
> Werd wohl beizeiten mal eine uralte linux live cd probieren müssen,
> um zu sehen, ob es mit einer entsprechend alten bash auch unter
> linux schiefging.
>
Unter Linux (RHES) tritt der Fehler bei mir nicht auf (bash
3.00.15(1)-release), sehr wohl aber unter AIX (sogar noch
schneller). Dürfte auch eine Frage der Rechnergschwindigkeit
sein.

BTW: bei Auftreten eines Fehlers zeigt lsof bei mir an die 2000
offene Dateien für den user, während Normalbetrieb ca. 250.

lg. jakob
Message has been deleted

Bernd Petrovitsch

unread,
Dec 9, 2011, 8:25:49 AM12/9/11
to
On Thu, 08 Dec 2011 11:02:16 +0100, David Wührer wrote:
> Bernd Petrovitsch wrote:
>> On Thu, 01 Dec 2011 12:47:14 +0100, David Wührer wrote:
>>> Bernd Petrovitsch wrote:
>>>> On Tue, 29 Nov 2011 17:20:35 +0100, David Wührer wrote:
>
>> Du hast eine erschreckende komische Vorstellung von Hardware.
>
> Wie viele Pages parallel kann eine Festplatte schreiben?

- Hängt von der Festplatte ab.
- "Parallel" in welchem Sinne bzw. auf welcher Ebene/Layer?

Hat der OP überhaupt etwas von einer Festplatte geschrieben?
Der hat das Filesystem drunter - WIMRE - gar nicht erwähnt.

>> ?? Zuerts versuchst Du, Cache-Kohärenz-Probleme zu konstruieren und dann
>> wird der n+1. Cache ignoriert?
>
> Weil das ein völlig anderer Cache an einer völlig anderen Stelle ist.
> Wäre die Festplatte oder deren Cache kaputt, würde es mit ksh auch nicht
> gehen.

Selbiges gilt für den Page-Cache, Buffer-Cache, 1st und 2nd-Level-RAM-Cache,
die Pipeline und Register der CPU (und ich hab bestimmt noch irgendwo einen
Cache iwS vergessen ....).

>> Ja, aber die existiert unter dem VFS-Layer und der gesamte User-Space
>> sieht über den einzigen VFS dasselbe von drunter existierenden Diskspace.
>
> Was nicht bedeutet, dass die Geräte darunter sich auch identisch verhalten.

Das ist der Job (und der originäre Sinn) des Gerätetreibers, daß sich die
Geräte drunter "identisch verhalten" - und zwar so, wie es der VFS von oben
vorgibt. Und oberhalb des VFS verhält sich alles identisch - sonst hätte
der VFS ja keinen (besonderen) Sinn.

> Aber da der Fehler in der RAM-Disk genauso auftritt, liegt er wohl nicht an
> irgend einem Gerät.

An der RAM-Disk - die ist auch ein "Gerät" (wenn es als deutsche Übersetzung
von "Device" versteht).

Ist das Verhalten verschieden, wenn man das Filesystem drunter wechselt?
Da von kann ich nirgendwo etwas finden.

>> Die ksh verläßt sich auf den Kernel - in Ermangelung von Alternativen.
>
> So wenig wie möglich.

Aber am Sys-Call-Layer kommt die auch nicht vorbei - und das ist so minimal
wie möglich.

> Dateien werden zwar mit open() geöffnet, aber die ksh merkt sich auch, von
> welchem Dateisystem (das dann dort disc heißt) jede Datei stammt.
> Synchronisiert werden die Dateien über eigene Mutexes, und geschrieben mit
> memmove(). read() und write() werden nicht gebraucht.

Die mmap()ed die Files? Oder wie kommen der Inhalt des Files in den Adreßraum
des Prozesses?
Und ja, ich will hier Sys-Calls (inkl. relevanter Parameter) lesen und keine
flapsigen Ausdrücke, die mehrere verschiedenen Interpretationen zu lassen,

> Die Funktionalität des Betriebssystems wird also dupliziert.

Tja, ein Punkt mehr, die ksh nicht zu verwenden.

> Nicht die gesamte natürlich, aber der Teil, der sich um die logische
> Integrität von Dateien kümmert, und ein Teil der Optimierung des
> Zurückschreibens von Daten.

Das ist mbMn ein großer strategischer Fehler, daß eine Applikation auf
einem relativ hohen Layer versucht, intelligenter wie die drunteren zu
sein und das ohne spezielles Wissen bzw. Annahmen über die drunteren
Layer. Vom "optimieren" (was immer das im Detail wirklich meint) mal
ganz abgesehen. Tja ....

>> Abgesehen davon hat die Existenz vs Nicht-Existenz eines Files nichts mit
>> der Implementierung einer stdio-Lib zu tun - die verwendet unten ja auch
>> nur open(2) und entweder geht das gut oder nicht.
>
> Sobald eine Datei gelöscht oder überschrieben wird, während sie geöffnet
> oder gelesen wird, hängt das schon von der Implementierung ab.

Am Sys-Call-Layer kenn' ich nur eine korrekte Implementierung (die mbMn von
POSIX zwingend die Folge ist - bzw. umgekehrt):
- Das obige flapsige untechnische "File wird gelöscht" heißt ja in
technischer Realität nur, daß der Hardlink vom (später gelöschten)
Filenamen zum Inode entfernt wird (und sonst nichts anderes!).
Gibt es weitere Hardlinks, gibt es das File weiter (und wenn nicht, wird
es gelöscht und der verbrauchte Diskspace freigegeben, wenn der letzte
Prozeß, der es verwendet hat, das File geschlossen hat).
Und wenn das File von anderen Prozessen geöffnet wurde, ändert sich für
diese Prozesse auch nichts - die können weiter drauf lesen, schreiben,
etc. unabhängig davon, ob der Linkcount == 0 oder != 0 ist.
Und ob es 2 Sekunden später den Filenamen wieder gibt, ist auch
unerheblich.
- Das obige flapsige untechnische "File wird überschrieben" interpretier'
ich als "read/write-Öffen und dann drauf schreiben".
Da ändert sich am File als solchem nur der Inhalt und ein paar Meta-Daten
(wie z.B. Last-Modified-Time und u.U. die Größe).
Alle *Prozesse*, die dasselbe File auch offen haben, sehen die Änderungen
nach einem write(2) bzw. - wenn der Prozeß es ge-mmap(2)t hat - (spätestens)
nach einem msync(2) ganz egal, ob bzw. wann das auf etwaiger Hardware
landet.
Das "nach einem" ist spätestens bei Multi-Core-CPUs u.ä. nicht näher
definierbar (aber letztendlich auch auf Single-CPU-Systemen nicht - hängt
ja immer vom Scheduling ab .....).
Aber in dem Fall, daß mehrere Prozesse (potentiell) parallel den Inhalt des
*selben* Files verändern, muß man sich um die Synchronisation sowieso
Gedanken machen und das auf Applikationsebene lösen - das geht weiter unten
ja sowieso nicht, daß der Kernel Synchronisation im Sinne einer Applikation
macht.

Und das ist das Verhalten am Sys-Call-Level und es spielt keine Rolle, ob das
Filesystem drunter irgendeine Art von RAM-Disk oder echter Festplatte oder
NAND-Flash ist.

> In diesem Fall wird eine Datei mehrere hundert Mal geöffnet, geschrieben und
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> geschlossen, aber die ksh macht genau ein open() dafür.
^^^^^^^^^^
Magst Du das nicht etwas (wenigstens in sich) widerspruchfreies hinschreiben?

Inhaltlich ist es auch falsch i.Ü. - da wird jedesmal ein neues File geöffnet.
Diese verschiedenen Files haben halt denselben Filenamen den es dazwischen
kurzzeitig nicht gibt.

>> Ah ja, das Rad neu erfunden und parallel implementiert ....
>
> Und einen Bug vermieden oder umgangen dabei, wie es scheint.

Ein Bug in der bash wird umgangen, in dem die ksh verwendet wird?
Oh welch Wunder ...
Oder was *genau* hast Du gemeint?

Daß die ksh-Entwickler Code schreiben, der eine Linux-Kernel-Bug kaschiert?
Daß mehrere unixoide Kernels denselben "Bug" haben und deshalb in der ksh
Code steht, der um diesen herumarbeitet?

Andreas Leitgeb

unread,
Dec 10, 2011, 8:24:00 AM12/10/11
to
Bernd Petrovitsch <be...@tuxoid.at> wrote:
> On Thu, 08 Dec 2011 11:02:16 +0100, David Wührer wrote:
>> Wie viele Pages parallel kann eine Festplatte schreiben?
> Hat der OP überhaupt etwas von einer Festplatte geschrieben?

Mit meinem OPosting hat dieser subthread eh nix mehr zu tun ;-)

Andreas Leitgeb

unread,
Dec 10, 2011, 8:37:00 AM12/10/11
to
jakob kollmann <jakob.k...@filofant.org> wrote:
> On 12/4/2011 11:14 PM, Andreas Leitgeb wrote:
>> Werd wohl beizeiten mal eine uralte linux live cd probieren müssen,
>> um zu sehen, ob es mit einer entsprechend alten bash auch unter
>> linux schiefging.
> Unter Linux (RHES) tritt der Fehler bei mir nicht auf (bash
> 3.00.15(1)-release),

Hmm, Dann scheint der bash-bug also doch eine gewisse OS-abhaengigkeit
zu haben...

> sehr wohl aber unter AIX (sogar noch
> schneller). Dürfte auch eine Frage der Rechnergschwindigkeit
> sein.

Naja, wenn alles konsistent im Zeitraffer laeuft... :-)

Danke für den alt-linux und AIX test.

> BTW: bei Auftreten eines Fehlers zeigt lsof bei mir an die 2000
> offene Dateien für den user, während Normalbetrieb ca. 250.

lsof wollte ich drauf ansetzen, aber die Prozesse in dem kontext,
die ich kurz vorher lsof'te, hatten allesamt unter 10 fd's offen.
(dabei hatte ich sogar eine pstree-lsof konstruktion drin, die
alle beteiligten prozesse finden und checken sollte - aber die
messmethode war wohl nicht genug ausgereift.)

Wie hast du den lsof gestartet, um die 2000 offenen dateien zu sehen?
Message has been deleted

Andreas Leitgeb

unread,
Dec 12, 2011, 11:17:00 AM12/12/11
to
David Wührer <d...@gmx.at> wrote:
> Aber ohne das rm würde die bash eine bereits gelöschte Datei öffnen,

???
ohne rm wäre die Datei ja garnicht gelöscht.
Auch "> file" macht kein "unlink()", sondern nur open mit O_TRUNC

> Unter Linux zumindest kann immer nur ein Prozess gleichzeitig in eine
> bestimmte Datei schreiben.

Das glaube ich nicht.

>> Inhaltlich ist es auch falsch i.Ü. - da wird jedesmal ein neues File
>> geöffnet. Diese verschiedenen Files haben halt denselben Filenamen den es
>> dazwischen kurzzeitig nicht gibt.
> Nein, interessanterweise nicht. Die Datei (und in der ksh ist es nur eine)
> lebt die ganze Zeit im Speicher der ksh. Sogar die temporären Dateien, die
> anstelle von Pipes verwendet werden, werden in einem Pool der ksh verwaltet.

Von welchem Parallel-Universum schreibst du?

Bernd Petrovitsch

unread,
Dec 12, 2011, 12:43:27 PM12/12/11
to
On Mon, 12 Dec 2011 15:26:42 +0100, David Wührer wrote:
> Bernd Petrovitsch wrote:
>> On Thu, 08 Dec 2011 11:02:16 +0100, David Wührer wrote:
>>> Bernd Petrovitsch wrote:
>>>> On Thu, 01 Dec 2011 12:47:14 +0100, David Wührer wrote:
>>>>> Bernd Petrovitsch wrote:
>>>>>> On Tue, 29 Nov 2011 17:20:35 +0100, David Wührer wrote:
>>>
>>>> Du hast eine erschreckende komische Vorstellung von Hardware.
>>>
>>> Wie viele Pages parallel kann eine Festplatte schreiben?
>>
>> - Hängt von der Festplatte ab.
>> - "Parallel" in welchem Sinne bzw. auf welcher Ebene/Layer?
>
> In dem Layer, in dem die Festplatte mit dem Betriebssystem redet.

Also dem SCSI bzw. SATA bzw. sonstwas-Treiber. Welches Hardware hat
der OP?
Dann kannst Du rechcherchieren, wie das bei seiner Hardware wohl ist,
wenn Du der schon Bugs unterstellst ...

[...]
>>> Wäre die Festplatte oder deren Cache kaputt, würde es mit ksh auch nicht
>>> gehen.
>>
>> Selbiges gilt für den Page-Cache, Buffer-Cache, 1st und
>> 2nd-Level-RAM-Cache, die Pipeline und Register der CPU (und ich hab
>> bestimmt noch irgendwo einen Cache iwS vergessen ....).
>
> Verwechselst du Hardware mit Software?

Nein, ich hab nur weitere Caches aufgezählt. Die haben genauso
Zeitunterschiede wie "RAM vs Festplatte" (sonst gäbe es sie nicht).
Und auch nicht weniger Indizien für Bugs wie der Page Cache und Buffer
Cache.

[....]
>> Tja, ein Punkt mehr, die ksh nicht zu verwenden.
>
> Vorausgesetzt, sie ist nicht zufällig die einzige, mit der ein bash-
> kompatibles Skript richtig funktioniert.

*Ist* sie die einzige?
Oder nur die einzige, die Du gefunden hast (und welche anderen hast Du noch
ausprobiert)?

>> Das ist mbMn ein großer strategischer Fehler, daß eine Applikation auf
>> einem relativ hohen Layer versucht, intelligenter wie die drunteren zu
>> sein und das ohne spezielles Wissen bzw. Annahmen über die drunteren
>> Layer.
>
> Es sollte einfach unnötig sein.
> Wenn man schon weiß, dass der Layer, der das eigentlich machen sollte,
> defekt ist oder besser sein könnte, könnte man das gleich dort ausbessern.
> Vorausgesetzt, man hat den Quellcode und die Rechte dazu.

In einer Shell um Bugs im z.B. SATA-Treiber herumarbeiten?
Der Witz war gut.

>> - Das obige flapsige untechnische "File wird gelöscht" heißt ja in
>> technischer Realität nur, daß der Hardlink vom (später gelöschten)
>> Filenamen zum Inode entfernt wird (und sonst nichts anderes!).
>> Gibt es weitere Hardlinks, gibt es das File weiter (und wenn nicht, wird
>> es gelöscht und der verbrauchte Diskspace freigegeben, wenn der letzte
>> Prozeß, der es verwendet hat, das File geschlossen hat).
>
> Darum geht es hier aber gar nicht.
> Theoretisch sollte es für jeden Schleifendurchlauf eine neue Datei mit je
> genau einem Hardlink geben, die zufällig alle den selben Namen haben.

Du verwirrsst Dich erfolgreich mit Schleifendurchläufen und der OP hat
ganz ohne Schleife in
cmd1 | cmd2 > file; cmd3 < file
ein Problem.
Und es geht nur um diese eine Zeile, die gelegentlich nicht funktioniert.

Also, wo ist hier das "rm" bzw. - genauer - der "unlink()" Sys-Call?

[...]
>> Aber in dem Fall, daß mehrere Prozesse (potentiell) parallel den Inhalt
>> des *selben* Files verändern, muß man sich um die Synchronisation
>> sowieso Gedanken machen und das auf Applikationsebene lösen - das geht
>> weiter unten ja sowieso nicht, daß der Kernel Synchronisation im Sinne
>> einer Applikation macht.
>
> Unter Linux zumindest kann immer nur ein Prozess gleichzeitig in eine
> bestimmte Datei schreiben.

Dann erklär den Output von
while :; do echo "aaa"; done >>~/xxx & x=$!; \
while :; do echo "bbb"; done >>~/xxx & y=$!; \
sleep 2; kill $x $y; cat ~/xxx
.
Danke.

Du kannst auch gerne noch "sync" nach Belieben einstreuen oder s/~/\/tmp//
machen.

> Unter Windows kann man eine Datei nicht einmal löschen, während sie gelesen
> wird.

Da funktionieren Files am VFS-Layer auch subtil anders. Windows ist halt etwas
beschränkt.

> Ich sage, dass, wenn man das /wollte/, dass mehrere Prozesse gleichzeitig in
> die selbe Datei schreiben, das auch ein Betriebssystem /könnte/, aber
> normalerweise, wenn das passiert, ist sowieso etwas anderes kaputt, deshalb
> wozu der Aufwand, wenn eine Fehlerrückgabe hilfreicher ist.

Weil es Fälle gibt, wo es sinnvoll ist und auch funktioniert.

>> Und das ist das Verhalten am Sys-Call-Level und es spielt keine Rolle, ob
>> das Filesystem drunter irgendeine Art von RAM-Disk oder echter Festplatte
>> oder NAND-Flash ist.
>
> Eine Festplatte oder eine SSD sind an sich keine Filesysteme.
> Ich nehme an, das wusstest du schon.

Ja, der Satz hätte sein sollen:
Und das ist das Verhalten am Sys-Call-Level und es spielt keine Rolle, ob
das Filesystem drunter *auf* irgendeiner Art von RAM-Disk oder echter
Festplatte oder NAND-Flash ist.

Es gibt ja da jeweils mehrere Möglichkeiten für "Filesystem" auch noch ....

> Was passiert deiner Meinung nach, wenn der Dateipuffer für ein Gerät
> schneller gefüllt wird, als die Daten zurückgeschrieben werden können?

Was ist ein "Dateipuffer" bzw. mit wlechen Sys-Calls operiert man auf dem?

[...]
>>> In diesem Fall wird eine Datei mehrere hundert Mal geöffnet, geschrieben
>>> und
>> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> geschlossen, aber die ksh macht genau ein open() dafür.
>> ^^^^^^^^^^
>> Magst Du das nicht etwas (wenigstens in sich) widerspruchfreies
>> hinschreiben?
>
> Ein Sub-Prozess öffnet eine Datei, ohne dass die Shell, in der das läuft,
> den entsprechenden Sys-Call macht. Was ist daran so schwer zu verstehen?

Mit einem open() kann man ein File nicht hundert Mal öffnen - nicht mal die
ksh bzw. deren Subprozesse.
Und wenn ein Subprozeß open() macht, wie kann wer anderer reinschreiben?

[.... unkonstruktiver Schluß gelöscht .....]

Andreas Leitgeb

unread,
Dec 12, 2011, 1:27:32 PM12/12/11
to
Bernd Petrovitsch <be...@tuxoid.at> wrote:
>>> Tja, ein Punkt mehr, die ksh nicht zu verwenden.

Was auch immer da der Punkt war, es war kein relevanter.
Es gibt ein paar Gründe, die ksh nicht zu verwenden, aber
ein *angebliches* seltsames Verhalten ohne Beweis kann wohl
kaum einer sein.

> Du verwirrsst Dich erfolgreich mit Schleifendurchläufen und der OP hat
> ganz ohne Schleife in
> cmd1 | cmd2 > file; cmd3 < file
> ein Problem.
> Und es geht nur um diese eine Zeile, die gelegentlich nicht funktioniert.

Es ist nicht ganz so einfach, wie ich bereits kurz danach erklärte.
Die Schleife spielte jedenfalls mehr Rolle als nur zur Wiederholung
"unabhängiger" Einzel-tests.

Message has been deleted
Message has been deleted

Adalbert Michelic

unread,
Dec 14, 2011, 4:33:49 AM12/14/11
to
* On 2011-12-14, David Wührer wrote:
> Bernd Petrovitsch wrote:

>> Dann erklär den Output von
>> while :; do echo "aaa"; done >>~/xxx & x=$!; \
>> while :; do echo "bbb"; done >>~/xxx & y=$!; \
>> sleep 2; kill $x $y; cat ~/xxx
>> .
>
> Jedes 'echo "aaa"' und 'echo "bbb"' ist ein eigener Prozess.
> Während eines davon schreibt, kann kein anderes schreiben,
> sonst hätte man nicht jedes "aaa" und "bbb" in einer eigenen Zeile.

Bernds Beispiel ist in der Tat nicht sehr geeignet, um zu zeigen,
dass Prozesse gleichzeitig schreiben koennen - aber Deine Annahme
ist auch falsch.

Dass der Inhalt in seperaten Zeilen landet, liegt an der
Puffergroesse und an open(..., O_APPEND).

Siehe
http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html
und den Abschnitt ueber atomic/non-atomic.

Und ja, bei NFS geht das in Hose.

>> Mit einem open() kann man ein File nicht hundert Mal öffnen - nicht mal
>> die ksh bzw. deren Subprozesse.

Hae, wieso?

wget -O writetest.c http://pastebin.com/raw.php?i=zRgdhLtz
gcc -o writetest writetest.c
./writetest 100000 & ./writetest 100000 & ./writetest 100000

3 Prozesse, die gleichzeitig in die gleiche Datei schreiben - immer
schoen hinten dran. Gerne auch mit 100 Prozessen.

Man kann das ganze auch mit einem laengeren Puffer als PIPE_BUF (und
mehr Inhalt) probieren - und wird dann sehen, dass die Zeilen
zerschossen werden.


Adalbert

Andreas Leitgeb

unread,
Dec 14, 2011, 5:16:19 AM12/14/11
to
David Wührer <d...@gmx.at> wrote:
> Andreas Leitgeb wrote:
>> David Wührer <d...@gmx.at> wrote:
>>> Nein, interessanterweise nicht. Die Datei (und in der ksh ist es nur eine)
>>> lebt die ganze Zeit im Speicher der ksh. Sogar die temporären Dateien, die
>>> anstelle von Pipes verwendet werden, werden in einem Pool der ksh verwaltet.
>> Von welchem Parallel-Universum schreibst du?
> Von der korn shell.

Von der ksh in welchem parallel-Universum?

truss -f -o ksh.log ksh -c "/bin/echo foo > fubar; /bin/head -1 < fubar"
relevante Auszüge aus ksh.log:
7667: fork1() = 7670
7670: open64("fubar", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
7670: close(1) = 0
7670: fcntl(3, F_DUPFD, 0x00000001) = 1
7670: close(3) = 0
7670: execve("/bin/echo", 0x00059004, 0x000590A8) argc = 2
7670: fstat64(1, 0xFFBFE488) = 0
7670: write(1, " f o o\n", 4) = 4
7670: _exit(0)
7667: open64("fubar", O_RDONLY) = 3
7667: close(0) = 0
7667: fcntl(3, F_DUPFD, 0x00000000) = 0
7667: close(3) = 0
7667: execve("/bin/head", 0x00059094, 0x000590B0) argc = 2
7667: fstat64(0, 0xFFBFE118) = 0
7667: read(0, " f o o\n", 8192) = 4
7667: ioctl(1, TCGETA, 0xFFBFD56C) = 0
7667: fstat64(1, 0xFFBFD488) = 0
7667: write(1, " f o o\n", 4) = 4
7667: _exit(0)

Interessant, dass die ksh gneisst, dass head das letzte kommando
ist, und keinen fork() mehr dafuer macht. Aber dass das redirection-
file einmal geöffnet und dann ge'mmap't wuerde, also davon ist im
hiesigen Universum nichts zu erkennen.

Bitte um den entsprechenden anderen Testfall, der das von dir
behauptete Verhalten zeigt.

Bernd Petrovitsch

unread,
Dec 14, 2011, 9:05:34 PM12/14/11
to
On Wed, 14 Dec 2011 09:14:44 +0100, David Wührer wrote:
> Bernd Petrovitsch wrote:
>> Also dem SCSI bzw. SATA bzw. sonstwas-Treiber. Welches Hardware hat
>> der OP?
>> Dann kannst Du rechcherchieren, wie das bei seiner Hardware wohl ist,
>> wenn Du der schon Bugs unterstellst ...
>
> Das tue ich nicht.
>
> Ich unterstelle nicht, dass die Gerätetreiber kaputt sind, sondern dass eine

OK.

> Race Condition existiert, die erst dann Fehler produziert, wenn sich am
> Timing zwischen quasi unabhängigen Systemen etwas ändert. Konkret, wenn ein
> System nach zehn Sekunden anfängt, länger für etwas zu brauchen.

Also wo *genau* soll dann was buggy sein, wenn es Treiber im Kernel nicht
sind?

[....]

>> Nein, ich hab nur weitere Caches aufgezählt. Die haben genauso
>> Zeitunterschiede wie "RAM vs Festplatte" (sonst gäbe es sie nicht).
>> Und auch nicht weniger Indizien für Bugs wie der Page Cache und Buffer
>> Cache.
>
> Eigentlich doch, weil wie gesagt, wenn die etwas hätten, würden noch ganz
> woanders ganz andere Fehler auftreten.

Und genau dasselbe Argument gilt für das unterstellte Page-Cache-Problem.

>> *Ist* sie die einzige?
>
> Das weiß ich nicht.

Tja, warum behauptest Du es dann?
Mag sein, daß Du es so nicht nicht gemeint hast, aber das Wording ist
- ähemm - ziemlich eindeutig.

[...]
>> In einer Shell um Bugs im z.B. SATA-Treiber herumarbeiten?
>> Der Witz war gut.
>
> Leider kein Witz. Es wird oft unnötig um Bugs herumgearbeitet, weil man das
> System darunter nicht verändern kann oder darf.

Am Layer X um Bugs im Layer X-5 (oder so) herumarbeiten, wo dazwischen
auch noch Caches liegen ist - vorsichtig formuliert - mutig.
Am Layer drunter, geht ja noch. Aber wenn mehrere Layers dazwischen sind,
da sollte man schon genau wissen, was jeder Layer tut und wie die
interagieren, bevor man versucht, noch schlauer zu sein.
Vom Testaufwand und Restrisiko mal ganz abgesehen ....

>> Dann erklär den Output von
>> while :; do echo "aaa"; done >>~/xxx & x=$!; \
>> while :; do echo "bbb"; done >>~/xxx & y=$!; \
>> sleep 2; kill $x $y; cat ~/xxx
>> .
>
> Jedes 'echo "aaa"' und 'echo "bbb"' ist ein eigener Prozess.

`echo` ist zwar ein Shell-Built-In in so gut wie jeder Shell, aber
das stört nicht oder ändert nichts, wenn es /bin/echo wäre.

> Während eines davon schreibt, kann kein anderes schreiben,

???? Die 2 while-Schleifen laufen quasi-parallel.

> sonst hätte man nicht jedes "aaa" und "bbb" in einer eigenen Zeile.

Die einfachere Erklärung ist, daß da irgendwo was line-buffered
ist.

Wo geht der Output der "echo"s hin - unabhängig jeglicher Bufferung?

In das eine File, daß durch das ">>" genau 2 Mal - einmal für jeden
while-Loop - geöffnet wurde.
Auch wenn es open(..., O_APPEND) ist, ist es 2 Mal zugleich geöffnet
und 2 verschiedene Prozesse (die, die mit "&" im Hintergrund laufen)
schreiben parallel hinein.
Was Deiner Meinung nach ja gar nicht geht.
q.e.d.

>> Danke.
>
> Bitte.

Der war auch gut.

[....]
> Außerdem kann über das SCSI- bzw ATA-Protokoll nur blockweise gelesen und
> geschrieben werden. Entweder man wartet, bis ein Block voll ist, oder man
> füllt den Block auf, wenn keine Daten nachkommen.

Und schon wieder über mehrere Layers Pauschalaussagen. Ich kommentier das
jetzt nicht weiter, weil es eh nichts bringt.

>> Mit einem open() kann man ein File nicht hundert Mal öffnen - nicht mal
>> die ksh bzw. deren Subprozesse.
> So gesehen wird die Datei nur einmal geöffnet, von der ksh.

q.e.d.
Du willst den Absatz u.U., wo das her ist, u.U. neu formulieren.
Message has been deleted
Message has been deleted

Andreas Leitgeb

unread,
Dec 21, 2011, 8:22:46 AM12/21/11
to
> Ich habe keinen, ich habe im Quellcode nachgeschaut, was mit den Dateien
> gemacht wird.

Im Source einer open-source ksh, oder im Source von der Solaris-ksh?

0 new messages