fix(storage): harden disk operations, add volume labels, and stabilize AHCI discovery
This commit is contained in:
1 parent
7e99bc2db1
commit
d1ecd3fc41
18 files changed
+1563
-1493
No files matched your search
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -154,7 +154,8 @@ type
|
||||
sleVolumeInvalidated,
|
||||
sleVolumeRemoved,
|
||||
sleDeviceAdded,
|
||||
sleDeviceRemoved
|
||||
sleDeviceRemoved,
|
||||
sleVolumeLabelChanged
|
||||
);
|
||||
|
||||
TStorageLifecycleCallback = procedure(event : TStorageLifecycleEvent;
|
||||
@@ -163,6 +164,8 @@ type
|
||||
error : TError;
|
||||
userdata : pointer);
|
||||
|
||||
TVolumeLabel = array[0..32] of char; { cached, NUL-terminated display name }
|
||||
|
||||
TFSFormatParams = record
|
||||
Version : uint16;
|
||||
Flags : uint16;
|
||||
@@ -186,13 +189,15 @@ type
|
||||
TIOCallback = procedure(error : TError; userdata : pointer);
|
||||
|
||||
{ Filesystem callback core.types }
|
||||
PPCreateHook = procedure(volume : PStorage_volume; start : uint32; size : uint32; config : PFSFormatParams);
|
||||
PPCreateHook = function(volume : PStorage_volume; sectors : uint32; start : uint32; config : PFSFormatParams) : TError;
|
||||
PPCreateAsyncHook = procedure(volume : PStorage_volume; start : uint32; size : uint32; config : PFSFormatParams; callback : TIOCallback; callbackData : pointer);
|
||||
PPDetectHook = procedure(disk : PStorage_Device);
|
||||
PPCreateDirHook = procedure(volume : PStorage_volume; directory : pchar; dirname : pchar; attributes : uint32; status : puint32);
|
||||
PPReadDirHook = function(volume : PStorage_volume; directory : pchar; status : puint32) : PLinkedListBase;
|
||||
PPDeleteFileHook = procedure(volume : PStorage_Volume; filePath : pchar; status : puint32);
|
||||
PPDeleteDirHook = procedure(volume : PStorage_Volume; path : pchar; status : puint32);
|
||||
PPValidateLabelHook = function(text : pchar; var normalized : TVolumeLabel) : TError;
|
||||
PPSetLabelHook = function(volume : PStorage_Volume; text : pchar) : TError;
|
||||
PPIdentifyHook = function(volume : PStorage_Volume) : boolean;
|
||||
PPRenameFileHook = procedure(volume : PStorage_Volume; filePath : pchar; newName : pchar; status : puint32);
|
||||
{ Offset-based read: reads byteCount bytes starting at byte offset into the file.
|
||||
@@ -271,6 +276,8 @@ type
|
||||
maxSectorCount : uint32;
|
||||
sectorSize : uint32; //in bytes
|
||||
start : uint32; //start of device in sectors
|
||||
metadataBusy : boolean; { volume/partition operation owns device }
|
||||
mbrWriteBusy : boolean; { serializes staged sector-zero writes }
|
||||
cachedMBR : pointer; { cached mbr data, nil if not yet read }
|
||||
isBootDevice : boolean; { true if this is the device GRUB booted from }
|
||||
end;
|
||||
@@ -280,6 +287,7 @@ type
|
||||
sName : pchar;
|
||||
system_id : uint8;
|
||||
createCallback : PPCreateHook;
|
||||
validateFormat : PPCreateHook; { pure preflight, before invalidation }
|
||||
detectCallback : PPDetectHook;
|
||||
createDirCallback : PPCreateDirHook;
|
||||
readDirCallback : PPReadDirHook;
|
||||
@@ -304,6 +312,8 @@ type
|
||||
openFileCallback : PPOpenFileHook;
|
||||
closeFileCallback : PPCloseFileHook;
|
||||
formatParamFlags : uint32;
|
||||
validateLabelCallback : PPValidateLabelHook;
|
||||
setLabelCallback : PPSetLabelHook;
|
||||
end;
|
||||
|
||||
{ Generic storage volume }
|
||||
@@ -317,6 +327,7 @@ type
|
||||
filesystem : PFilesystem;
|
||||
isBootDrive : boolean;
|
||||
lifecycleFlags : uint32;
|
||||
labelText : TVolumeLabel;
|
||||
fsPrivate : pointer; { FS-driver private data (e.g. PFATCache for FAT32) }
|
||||
end;
|
||||
|
||||
|
||||
@@ -134,6 +134,7 @@ procedure UnwatchDirectory(WatchID : uint32);
|
||||
{ Volume invalidation — must be called before freeing a volume.
|
||||
Closes all open FDs referencing the volume across all processes,
|
||||
evicts directory cache entries, and removes VFS mount points. }
|
||||
function VolumeHasOpenHandles(vol : PStorage_Volume) : boolean;
|
||||
function InvalidateVolume(vol : PStorage_Volume) : boolean;
|
||||
|
||||
{ VFS Functions }
|
||||
@@ -509,7 +510,7 @@ end;
|
||||
function GetObjectFromPath(path : pchar) : PVFSObject; forward;
|
||||
function GetObjectFromPathEx(path : pchar; var volRelPath : pchar) : PVFSObject; forward;
|
||||
|
||||
function volumeHasAsyncHandles(vol : PStorage_Volume) : boolean;
|
||||
function volumeHasHandles(vol : PStorage_Volume; asyncOnly : boolean) : boolean;
|
||||
var
|
||||
pCount : uint32;
|
||||
pi : uint32;
|
||||
@@ -517,7 +518,7 @@ var
|
||||
pCtx : proc.types.PProcessContext;
|
||||
tbl : PFDTable;
|
||||
begin
|
||||
volumeHasAsyncHandles := false;
|
||||
volumeHasHandles := false;
|
||||
if vol = nil then exit;
|
||||
|
||||
pCount := proc.mgr.processCount();
|
||||
@@ -530,14 +531,17 @@ begin
|
||||
if tbl = nil then continue;
|
||||
for fi := 0 to MAX_FDS - 1 do begin
|
||||
if tbl^.Entries[fi].InUse and (tbl^.Entries[fi].Volume = vol)
|
||||
and (tbl^.Entries[fi].AsyncRefs > 0) then begin
|
||||
volumeHasAsyncHandles := true;
|
||||
and ((not asyncOnly) or (tbl^.Entries[fi].AsyncRefs > 0)) then begin
|
||||
volumeHasHandles := true;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function VolumeHasOpenHandles(vol : PStorage_Volume) : boolean;
|
||||
begin VolumeHasOpenHandles := volumeHasHandles(vol,false); end;
|
||||
|
||||
function InvalidateVolume(vol : PStorage_Volume) : boolean;
|
||||
var
|
||||
pCount : uint32;
|
||||
@@ -554,7 +558,7 @@ begin
|
||||
debug.tracer.push_trace('driver.storage.vfs.InvalidateVolume.enter');
|
||||
InvalidateVolume := false;
|
||||
if vol = nil then exit;
|
||||
if volumeHasAsyncHandles(vol) then begin
|
||||
if volumeHasHandles(vol,true) then begin
|
||||
debug.tracer.push_trace('driver.storage.vfs.InvalidateVolume.busy');
|
||||
exit;
|
||||
end;
|
||||
@@ -986,6 +990,7 @@ begin
|
||||
volumeGetDirectories := nil;
|
||||
|
||||
if vol = nil then exit;
|
||||
if (vol^.device = nil) or vol^.device^.metadataBusy or driver.storage.vol.mgr.volume_is_busy(vol) then exit;
|
||||
if vol^.filesystem = nil then exit;
|
||||
if vol^.filesystem^.readDirCallback = nil then exit;
|
||||
|
||||
@@ -1153,6 +1158,15 @@ begin
|
||||
exit;
|
||||
end;
|
||||
|
||||
mountObj := PVFSObject(core.ds.hashmap.get(ht, mountName));
|
||||
if mountObj <> nil then begin
|
||||
if (mountObj^.ObjectType = otDRIVE) and (mountObj^.Reference = void(volume)) then begin
|
||||
mountVolume := pvRegistered;
|
||||
driver.storage.vol.mgr.volume_set_mounted(volume, true);
|
||||
end;
|
||||
kfree(void(parentPath)); STRLL_Free(splitPath); exit;
|
||||
end;
|
||||
|
||||
{ Create the mount object storing the volume pointer }
|
||||
mountObj := PVFSObject(kalloc(sizeof(TVFSObject)));
|
||||
|
||||
@@ -1219,6 +1233,12 @@ begin
|
||||
end;
|
||||
|
||||
volOut^ := PStorage_Volume(Obj^.Reference);
|
||||
if (volOut^ = nil) or (volOut^^.device = nil) then begin
|
||||
if volRel <> nil then kfree(void(volRel)); exit;
|
||||
end;
|
||||
if volOut^^.device^.metadataBusy or driver.storage.vol.mgr.volume_is_busy(volOut^) then begin
|
||||
if volRel <> nil then kfree(void(volRel)); volOut^ := nil; exit;
|
||||
end;
|
||||
|
||||
{ volRel is the path within the volume, e.g. '/mydir/myfile.txt' }
|
||||
if (volRel = nil) or StringEquals(volRel, '/') then begin
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -392,6 +392,15 @@ end;
|
||||
|
||||
{ ==================== Filesystem callbacks ==================== }
|
||||
|
||||
procedure cacheVolumeLabel(volume : PStorage_Volume; pvd : PPVD);
|
||||
var n, i : uint32;
|
||||
begin
|
||||
memset(uint32(@volume^.labelText[0]),0,sizeof(volume^.labelText));
|
||||
n := 32;
|
||||
while (n > 0) and ((pvd^.volumeId[n-1] = ' ') or (pvd^.volumeId[n-1] = #0)) do Dec(n);
|
||||
i := 0; while i < n do begin volume^.labelText[i] := pvd^.volumeId[i]; Inc(i); end;
|
||||
end;
|
||||
|
||||
{ Identify: check for 'CD001' at sector 16 }
|
||||
function identify_volume(volume : PStorage_Volume) : boolean;
|
||||
var
|
||||
@@ -405,6 +414,7 @@ begin
|
||||
buf := readSectors(volume^.device, volume^.sectorStart + PVD_SECTOR, 1);
|
||||
if buf = nil then exit;
|
||||
identify_volume := isPVD(buf);
|
||||
if identify_volume then cacheVolumeLabel(volume,PPVD(buf));
|
||||
kfree(buf);
|
||||
end;
|
||||
|
||||
@@ -437,6 +447,7 @@ begin
|
||||
volume^.filesystem := @filesystem;
|
||||
volume^.isBootDrive := disk^.isBootDevice;
|
||||
|
||||
cacheVolumeLabel(volume,pvd);
|
||||
driver.storage.vol.mgr.register_volume(disk, volume);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
@@ -94,10 +94,7 @@ end;
|
||||
|
||||
function fatMaxClusterCount(bootRecord : PBootRecord) : uint32;
|
||||
begin
|
||||
if (bootRecord = nil) or (bootRecord^.sectorSize = 0) then
|
||||
fatMaxClusterCount := 0
|
||||
else
|
||||
fatMaxClusterCount := (bootRecord^.FATSize * bootRecord^.sectorSize) div 4;
|
||||
fatMaxClusterCount := FAT32ClusterLimit(bootRecord);
|
||||
end;
|
||||
|
||||
function fatClustersForBytes(byteCount : uint32; bytesPerCluster : uint32) : uint32;
|
||||
@@ -391,7 +388,9 @@ begin
|
||||
sectorBuf := puint32(kalloc(bufSize));
|
||||
if sectorBuf = nil then exit;
|
||||
memset(uint32(sectorBuf), 0, bufSize);
|
||||
driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart, 1, sectorBuf);
|
||||
if driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart, 1, sectorBuf) <> eNone then begin
|
||||
kfree(sectorBuf); exit;
|
||||
end;
|
||||
bootRecord := PBootRecord(sectorBuf)^;
|
||||
kfree(sectorBuf);
|
||||
readBootRecordRaw := true;
|
||||
@@ -699,9 +698,13 @@ begin
|
||||
|
||||
{ Keep runtime addressing compatible with the legacy formatter and metadata paths. }
|
||||
ctx^.Info.DataStart := volume^.sectorStart + ctx^.Info.BootRecord.rsvSectors +
|
||||
ctx^.Info.BootRecord.FATSize;
|
||||
uint32(ctx^.Info.BootRecord.numFats) * ctx^.Info.BootRecord.FATSize;
|
||||
ctx^.Info.BytesPerCluster := uint32(ctx^.Info.BootRecord.spc) * uint32(ctx^.Info.BootRecord.sectorSize);
|
||||
ctx^.Info.MaxCluster := fatMaxClusterCount(@ctx^.Info.BootRecord);
|
||||
if (ctx^.Info.MaxCluster <= 2) or
|
||||
(ctx^.Info.BootRecord.manySectors > volume^.sectorCount) then begin
|
||||
fatCtxFree(ctx); exit;
|
||||
end;
|
||||
ctx^.InfoValid := true;
|
||||
|
||||
ctx^.Cache.Data := puint32(kalloc(FAT_CACHE_LINES * 512));
|
||||
@@ -1135,6 +1138,7 @@ begin
|
||||
end;
|
||||
if dir^.fileName[0] = char($E5) then
|
||||
continue;
|
||||
if (dir^.attributes and $08) <> 0 then continue; { volume labels and LFN entries are not files }
|
||||
if compareByteArray8(dir^.fileName, cleanName) and matchExtension(dir^.fileExtension, ext) then begin
|
||||
findEntryInSector := integer(idx);
|
||||
exit;
|
||||
@@ -2048,7 +2052,7 @@ begin
|
||||
end;
|
||||
if dir^.fileName[0] = char($E5) then
|
||||
continue;
|
||||
if dir^.attributes = $0F then
|
||||
if (dir^.attributes and $08) <> 0 then
|
||||
continue;
|
||||
if fatIsDotEntry(dir) then
|
||||
continue;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -16,6 +16,7 @@ uses
|
||||
io.syslog,
|
||||
core.util,
|
||||
driver.storage.fs.fat32.vol,
|
||||
driver.storage.fs.fat32.labels,
|
||||
driver.storage.fs.fat32.core,
|
||||
driver.storage.fs.fat32.transfer;
|
||||
|
||||
@@ -36,7 +37,8 @@ begin
|
||||
filesystem.readDirCallback := @FAT32ReadDirectory;
|
||||
filesystem.createDirCallback := @FAT32CreateDirectory;
|
||||
filesystem.createCallback := @create_volume;
|
||||
filesystem.createAsyncCallback := @create_volume_async;
|
||||
filesystem.validateFormat := @validate_format;
|
||||
filesystem.createAsyncCallback := nil; { volume manager runs checked formatter in a worker }
|
||||
filesystem.detectCallback := @detect_volumes;
|
||||
filesystem.readOffsetCallback := @FAT32ReadFileAtOffset;
|
||||
filesystem.writeOffsetCallback := @FAT32WriteFileAtOffset;
|
||||
@@ -51,7 +53,9 @@ begin
|
||||
filesystem.closeFileCallback := @FAT32CloseFile;
|
||||
filesystem.createDirAsyncCallback := nil;
|
||||
filesystem.readDirAsyncCallback := nil;
|
||||
filesystem.formatParamFlags := FS_FORMAT_PARAM_CLUSTER_SIZE;
|
||||
filesystem.formatParamFlags := FS_FORMAT_PARAM_CLUSTER_SIZE or FS_FORMAT_PARAM_LABEL;
|
||||
filesystem.validateLabelCallback := @normalize_label;
|
||||
filesystem.setLabelCallback := @write_label;
|
||||
|
||||
FAT32VolInit(@filesystem);
|
||||
driver.storage.fs.mgr.register_filesystem(@filesystem);
|
||||
|
||||
@@ -224,6 +224,28 @@ type
|
||||
WriteRefs : array[0..FAT_OPEN_HANDLE_SLOTS - 1] of TFATWriteRef;
|
||||
end;
|
||||
|
||||
{ Exclusive cluster bound, constrained by both data area and FAT capacity. }
|
||||
function FAT32ClusterLimit(br : PBootRecord) : uint32;
|
||||
|
||||
implementation
|
||||
|
||||
function FAT32ClusterLimit(br : PBootRecord) : uint32;
|
||||
var overhead, total, capacity, limit : uint64;
|
||||
begin
|
||||
FAT32ClusterLimit := 0;
|
||||
if br = nil then exit;
|
||||
if (br^.sectorSize <> 512) or (br^.spc = 0) or (br^.spc > 128) or
|
||||
((br^.spc and (br^.spc - 1)) <> 0) or (br^.rsvSectors = 0) or
|
||||
(br^.numFats = 0) or (br^.FATSize = 0) then exit;
|
||||
total := br^.manySectors;
|
||||
if total = 0 then total := br^.numSectors;
|
||||
overhead := uint64(br^.rsvSectors) + uint64(br^.numFats) * br^.FATSize;
|
||||
if overhead >= total then exit;
|
||||
limit := (total - overhead) div br^.spc + 2;
|
||||
capacity := uint64(br^.FATSize) * (br^.sectorSize div 4);
|
||||
if (limit > capacity) or (limit > $0FFFFFF0) then exit;
|
||||
FAT32ClusterLimit := uint32(limit);
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -86,7 +86,7 @@ procedure set_bootable(partition_table : PPartition_table);
|
||||
begin
|
||||
push_trace('driver.storage.vol.mbr.set_bootable');
|
||||
//set the bootble bit in attributes
|
||||
partition_table^.attributes := (partition_table^.attributes and $80);
|
||||
partition_table^.attributes := (partition_table^.attributes or $80);
|
||||
end;
|
||||
|
||||
{ Check a partitions bootable bit }
|
||||
@@ -105,7 +105,7 @@ begin
|
||||
partition_table^.LBA_start := address;
|
||||
partition_table^.sector_count := sectorSize;
|
||||
partition_table^.CHS_start := LBA_2_CHS(address);
|
||||
partition_table^.CHS_start := LBA_2_CHS(address + sectorSize);
|
||||
partition_table^.CHS_end := LBA_2_CHS(address + sectorSize - 1);
|
||||
push_trace('driver.storage.vol.mbr.setup_partition.end');
|
||||
end;
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user