Vad betyder allt det här? För Linuxanvändare bara en sak: att de måste se till att LILO och fdisk använder rätt geometri där "rätt" för fdisk är definierat som geometrin som används av de andra operativsystemen på samma hårddisk, och "rätt" för LILO definieras som geometrin som möjliggör lyckad interaktion med BIOSet vid uppstart. (Normalt sett sammanfaller dessa.)
Hur känner fdisk till geometrin? Den frågar kärnan genom att använda
ioctl:n HDIO_GETGEO
. Men användaren kan själv, interaktivt eller
på kommandoraden, bestämma vilken geometri som ska användas.
Hur känner LILO till geometrin? Den frågar kärnan genom att använda
ioctl:n HDIO_GETGEO
. Men användaren kan själv, med hjälp av
parametern "disk=
", bestämma vilken geometri som ska användas.
Man kan också ge parametern "linear
" till LILO, som då kommer att
lagra LBA-adresser istället för CHS-adresser i sin map-fil och räkna
ut vilken geometri som ska användas vid uppstart (genom att använda
INT 13 funktion 8 för att fråga om hårddiskgeometrin).
Hur vet kärnan vad den ska svara? Jo, användaren kan explicit ha
specificerat en geometri med en parameter som
hd=
cyls,
heads,
secs. Annars frågar
kärnan hårdvaran.
Låt mig utveckla mig. IDE-drivrutinen har fyra källor för information om geometrin. Den första (G_user) är den som användaren kan ha specificerat på kommandoraden. Den andra (G_bios) är BIOS' parametertabell (för fixa hårddiskar; bara för den första och den andra hårddisken) som läses innan bytet till 32-bitarsmod. Den tredje (G_phys) och fjärde (G_log) returneras av IDE-kontrollern som ett svar på kommandot IDENTIFY -- de är de "fysiska" och "nuvarande logiska" geometrierna.
Å andra sidan behöver drivrutinen två värden för geometrin: för det
första G_fdisk, som returneras av en HDIO_GETGEO
-ioctl, och för
det andra G_used, som faktiskt används för I/O. Både G_fdisk och
G_used initialiseras till G_user om den är given, till G_bios om
informationen finns tillgänglig enligt CMOS, och annars till G_phys.
Om G_log verkar vara rimlig sätts G_used till det. Annars, om G_used
inte verkar rimlig och G_phys ser rimlig ut, sätts G_used till G_phys.
Här betyder "rimlig" att antalet huvuden ligger i intervallet 1-16.
Med andra ord: kommandoraden har högre prioritet än BIOSet och bestämmer vad fdisk ser, men om det specificerar en översatt geometri (med fler än 16 huvuden) kommer det som returneras från IDENTIFY-kommandot att användas för kärn-I/O.
Situationen för SCSI är något annorlunda, eftersom SCSI-kommandona
redan använder logiska blocknummer, så en "geometri" är helt
irrelevant för I/O i praktiken. Formatet för partitionstabellen är
emellertid fortfarande samma, så fdisk måste uppfinna en geometri och
använder HDIO_GETGEO
här också -- faktiskt skiljer inte fdisk på
IDE- och SCSI-hårddiskar. Som man kan förstå från den detaljerade
beskrivningen nedan, uppfinner de olika drivrutinerna en något
annorlunda geometri. Helt klart en sagolik röra.
Om du inte använder DOS eller så, undvik alla inställningar rörande utökad översättning och använd bara 64 huvuden, 32 sektorer per spår (vilket ger trevliga 1 MB per cylinder), om möjligt, så att inga problem uppstår när du flyttar hårddisken från en kontroller till en annan. Vissa drivrutiner för SCSI-hårddiskar (aha152x, pas16, ppa, qlogicfas, qlogicisp) är så måna om att bibehålla DOS-kompatibilitet att de inte tillåter ett system som bara kör Linux att använda mer än 8 GB. Detta är en bugg.
Vad är den riktiga geometrin? Det lättaste svaret är att det inte finns någon sådan. Och om det fanns skulle du inte vilja vet något om den och säkerligen ALDRIG NÅGONSIN tala om den för fdisk eller LILO eller kärnan. Det är endast relevant för SCSI-kontrollern och hårddisken. Låt mig upprepa: bara dumma personer talar om den riktiga geometrin för en SCSI-hårddisk för fdisk/LILO/kärnan.
Men om du är nyfiken och insisterar kan du fråga hårddisken själv. Det finns det viktiga kommandot READ CAPACITY som ger den totala storleken på hårddisken och det finns kommandot MODE SENSE som i "Rigid Disk Drive Geometry Page" (sida 04) ger antalet cylindrar och huvuden (detta är information som inte går att ändra), och "Format Page" (sida 03) ger antal byte per sektor och antal sektorer per spår. Det sistnämnda antalet är typiskt beroende av notchen och antalet sektorer per spår varierar -- de yttre spåren har fler sektorer än de inre. Linuxprogrammet scsiinfo kan ge den här informationen. Det finns många detaljer och komplikationer och det står klart att ingen (inte ens operativsystemet) vill använda denna information. Dessutom: så länge man enbart bryr sig om fdisk och LILO får man typiskt svar som C/H/S=4476/27/171 -- värden som inte kan användas av fdisk eftersom partitionstabellen endast reserverar 10 respektive 8 respektive 6 bitar för C/H/S.
Så var får kärnanropet HDIO_GETGEO
sin information från? Jo,
antingen från SCSI-kontrollern eller genom att göra en kvalificerad
gissning. Några drivrutiner verkar tro att vi vill känna till
"verkligheten", men självklart vill vi bara veta vad FDISK i DOS eller
OS/2 (eller Adaptecs AFDISK, etc) kommer att använda.
Notera att Linux' fdisk behöver talen H och S (för huvuden och sektorer) för att kunna konvertera LBA-sektornummer till C/H/S-adresser, men talet C (cylindrar) spelar ingen roll i den här konverteringen. Några drivrutiner använder (C,H,S) = (1023,255,63) för att signalera att hårddiskkapaciteten är minst 1023*255*63 sektorer. Detta är olyckligt, eftersom det inte avslöjar den riktiga storleken, vilket kommer att begränsa användarna av de flesta fdisk-versionerna till att använda 8 GB av sina hårddiskar -- en riktig begränsning i dessa dagar.
I beskrivningen nedan står M för den totala hårddiskkapaciteten och C, H, S för antalet cylindrar, huvuden och sektorer per spår. Det räcker att ge H, S om vi betraktar C som definierad av M / (H*S).
Standardmässigt är H=64, S=32.
H=64, S=32.
H=64, S=32 om inte C > 1024, då H=255, S=63, C = min(1023, M/(H*S)). (Alltså trunkeras C och H*S*C är inte en approximation för hårddiskkapaciteten M. Detta gör de flesta fdisk-versioner förvirrade.) Koden i ppa.c använder M+1 istället för M och säger på grund av en bugg i sd.c att M är ett för lite.
H=64, S=32 om inte C > 1024 och "> 1 GB" är inställt i BIOS, då H=255, S=63.
Fråga kontrollern vilket av två möjliga sätt att översätta på som ska användas och använd antingen H=255, S=63 eller H=64, S=32. I det första fallet blir det ett boot-meddelande: "aha1542.c: Using extended bios translation".
H=64, S=32 om inte C > 1024 och antingen boot-parametern "extended" gavs eller att biten "extended" var satt i SEEPROM eller BIOS, då H=255, S=63.
H=64, S=32 om inte C >= 1024, och om utökad översättning är inställt på kontrollern, så är H=128, S=32 om M < 2^22, annars H=255, S=63. Efter att detta val har gjorts läses partitionstabellen och om värdet endH=H-1 syns för någon av de tre möjligheterna (H,S) = (64,32), (128,32), (255,63), blir det ett boot-meddelande: "Adopting Geometry from Partition Table".
Ta reda på geometriinformationen från parametertabellen för hårddiskar i BIOS eller läs partitionstabellen och använd H=endH+1, S=endS för den första partitionen, ifall den inte var tom, annars: använd H=64, S=32 för M < 2^21 (1 GB), H=128, S=63 för M < 63*2^17 (3,9 GB) och H=255, S=63.
Använd den första av (H,S) = (64,32), (64,63), (128,63), (255,63) som gör att C <= 1024. I det sista fallet, trunkera C vid 1023.
Läs C,H,S från hårddisken. (Iiiick!) Om C eller S är för stor, sätt S=17, H=2 och dubbla H tills C <= 1024. Detta innebär att H kommer att sättas till 0 om M > 128*1024*17 (1,1 GB). Detta är en bugg.
En av tre mappningar ((H,S) = (16,63), (64,32), (64,63)) används beroende på kontrollerns mappningsmod.
Kolla på partitionstabellen. Eftersom, per konvention, partitioner
slutar på en cylindergräns kan vi, givet end = (endC,endH,endS)
för vilken partition som helst, helt enkelt sätta H = endH+1
och
S = endS
. (Kom ihåg att sektorerna räknas från 1.) Mer precist
görs följande: Om det finns en icke-tom partition, välj den partition
med störst beginC
. Titta på end+1
för den partitionen,
beräknat genom att både addera start
och length
och genom
att anta att partitionen slutar på en cylindergräns. Om båda värdena
stämmer överens eller om endC
= 1023 och start+length
är en
heltalsmultipel av (endH+1)*endS
, anta att partitionen faktiskt
var placerad på en cylindergräns och sätt H = endH+1
och S =
endS
. Om detta inte fungerar, antingen på grund av att det inte
finns några partitioner eller på grund av att de har konstiga
storlekar, kolla bara på hårddiskkapaciteten M. Algoritm: sätt H =
M/(62*1024) (avrundat uppåt), S = M/(1024*H) (avrundat uppåt), C =
M/(H*S) (avrundat neråt). Detta ger en (C,H,S) med C högst 1024 och S
högst 62.