Een eigenschap van POSIX-filesystemen is dat ze met inodes werken, datastructuren in het filesysteem die het bestand beschrijven en los staan van directory's. Via het directory-pad van een bestand wordt een inode geïdentificeerd, en het bestand dat wordt geopend is aan de inode gekoppeld, niet aan het directory-pad.
Het effect daarvan kan je zien als je bijvoorbeeld een grote download doet, zeg van een ISO-image. Je hebt een download-locatie gekozen en nog voor de download klaar is bedenk je dat je de download ergens anders wilt hebben. Je kan
terwijl de download ongestoord doorloopt in een terminal met een mv-commando het bestand verplaatsen naar een andere directory in hetzelfde filesysteem. De download blijft ook op de nieuwe locatie toevoegen aan het bestand.
Een vergelijkbaar experiment is dit. Open drie terminalvensters. In een ervan monitor je het ruimtegebruik van je gemounte filesystemen:
watch -d df
In een tweede maak je een bestand aan dat alle beschikbare ruimte op gaat vreten in een filesysteem (tenzij je het afbreekt):
dd if=/dev/zero of=zero bs=1M
In de eerste terminal zie je dat het filesysteem waarop je dit doet geleidelijk minder ruimte heeft. In de derde terminal gooi je,
terwijl het dd-commando doorloopt, het bestand weg:
rm zero
Dat lukt gewoon, terwijl het dd-commando door blijft lopen en geleidelijk aan meer schijfruimte wordt gebruikt. Maar als het dd-commando eindigt (wegens een vol filesysteem of omdat je het met CTRL+C afbreekt) komt opeens de gebruikte schijfruimte weer beschikbaar.
Wat gebeurde daar? De bestandsnaam "zero" was gekoppeld aan een inode, en dd werkte met die inode. Een inode blijft bestaan zolang die in gebruik is, hetzij via een of meer verwijzingen ernaar in de directorystructuur, hetzij vanuit processen die het bestand geopend hebben. "rm zero" gooide dus wel de directoryverwijzing weg maar niet de inode, die verdween pas toen dd hem niet meer geopend hield, toen pas werd die niet meer gebruikt. In feite gooit rm helemaal geen bestanden weg, het verwijdert alleen directory-entries, en het is aan het filesysteem om te bepalen of het bestand zelf wordt weggegooid (en dat gebeurt als er nul verwijzingen naar zijn).
Dit maakt dat op POSIX-systemen (Unix, Linux) software bijgewerkt kan worden terwijl die in gebruik is (want ook een executable of library die actief is levert een referentie naar een inode op). De naam in de directory waar die staat verwijst na de upgrade naar een nieuwe inode, maar processen die de oude in gebruik hebben lopen niet stuk op het verdwijnen van het oude bestand
omdat de inode pas verdwijnt als die niet meer in gebruik is.
Linux heeft zo weinig reboots nodig omdat executables, libraries en andere bestanden die in gebruik zijn moeiteloos door nieuwe exemplaren kunnen worden vervangen. Het is na een upgrade wél nodig om processen die vervangen bestanden in gebruik hebben te herstarten, omdat die bestanden niet voor niets vervangen zijn en omdat er een (in de praktijk goed hanteerbaar) risico bestaat dat een oude versie van een executable na de upgrade een nieuwe versie van een library laadt waar die niet compatibel mee is. Bij bijvoorbeeld apache2 op Debian handelen de upgrade-scripts in het deb-pakket het af door de service voor de upgrade te stoppen en meteen erna weer te starten. Het pakket needrestart integreert een controle in het upgradeproces voor alle pakketten en biedt bij interactief gebruik een restart aan van alle services die met vervallen executables draaien, en geeft desktopgebruikers een notificatie van applicaties die een herstart nodig hebben.
Wat is er in Windows anders? Ik ben geen Windows-kenner, maar als ik het goed begrijp is in Windows een geopend bestand hard gekoppeld aan het directory-pad waarlangs het geopend is, en niet aan iets als een inode. Daardoor zijn bestanden ook op het niveau van een directory-pad gelockt, inclusief executables en libraries die aan lopende processen ten grondslag liggen, en is het vervangen van executables en libraries dus geblokkeerd. Een reboot is een botte-bijl-methode om in een klap
alle bestanden die in gebruik zijn vrij te geven, en mijn indruk is dat dat is hoe in vroegere versies van Windows deze situatie werd afgehandeld. Daar is (alweer mijn indruk) verbetering in aangebracht, maar men is er niet los van gekomen op de manier waarop de semantiek van POSIX-filesystemen dat mogelijk maakt.
Waarom neemt men die semantiek dan niet over in Windows? Filesystemen zelf zijn geen belemmering, onder Linux gedragen FAT en NTFS zich net zo als POSIX-filesystemen in dit opzicht, de Linux-drivers ervoor kunnen dit duidelijk gewoon aan. Maar ik kan me voorstellen dat Windows zelf en Windows-applicaties gebaseerd zijn op de aanname dat file-locks op directorypadniveau geregeld worden en dat men dat om compatibiliteitsredenen niet zomaar kan veranderen.
Ook is het bij de POSIX-semantiek heel makkelijk om te beredeneren wat er allemaal fout kan gaan, en moet je het in de praktijk hebben meegemaakt om te beseffen hoe goed dat probleem in de praktijk ondervangen is en hoe soepel het werkt.
En dan zijn er natuurlijk configuraties waarin het verschil niet belangrijk is. Als een service geïmplementeerd is op meerdere servers die achter een load balancer zitten en je bij upgrades sowieso niet alle servers parallel bijwerkt maar ze een voor een offline haalt, bijwerkt en weer opstart, dan maakt het buiten het verschil in doorlooptijd geen donder uit of er nou wel of geen reboot bij nodig is.