Hi Paulo, Sorry for the delayed response. The patch is good to me: Reviewed-by: Hao Wu <hao.a...@intel.com>
Hi Ray, Do you have any other comment on this? Best Regards, Hao Wu > -----Original Message----- > From: Paulo Alcantara [mailto:pca...@zytor.com] > Sent: Friday, October 13, 2017 9:25 PM > To: edk2-devel@lists.01.org > Cc: Paulo Alcantara; Wu, Hao A; Ni, Ruiyu; Zeng, Star; Dong, Eric > Subject: [PATCH] MdeModulePkg/PartitionDxe: Fix UDF fs access on certain > CD/DVD medias > > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=725 > > Historically many drives or medias do not correctly return their value > for block N - which is also referred as last addressable/recorded block. > When they do so, there is still a problem when relying on last recorded > block number returned by SCSI commands READ CAPACITY and READ TRACK > INFORMATION - that is, between block 0 and block N there may be > unwritten blocks which are located outside any track. > > That said, the Partition driver was unable to find AVDP at block N on > certain medias that do not either return or report their last recorded > block number correctly. > > Apparently there is no official or correct way to find the correct block > number, however tools like the Philips UDF Conformance Tool (udf_test) > apply a correction by searching for an AVDP or VAT in blocks N through > N-456 -- this can be observed by looking at the log reported by udf_test > on those CD/DVD medias. So, if the AVDP or VAT is found, then it sets > the last recorded block number to where AVDP or VAT was located. > > With the below setence in UDF 2.60, 6.13.2.2 Background Physical > Formatting: > > "... the second AVDP must be recorded after the Background physical > Formatting has been finished..." > > Implies that the last recorded block is the one where second AVDP was > recorded. > > This patch implements a similar way to correct the last recorded block > number by searching for last AVDP in blocks N-1 through N-512 on those > certain medias, as well as ensure a minimum number of 2 AVDPs found as > specified by ECMA 167 and UDF 2.60 specifications. > > Cc: Hao Wu <hao.a...@intel.com> > Cc: Ruiyu Ni <ruiyu...@intel.com> > Cc: Star Zeng <star.z...@intel.com> > Cc: Eric Dong <eric.d...@intel.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > Reported-by: Hao Wu <hao.a...@intel.com> > Signed-off-by: Paulo Alcantara <pca...@zytor.com> > --- > MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c | 254 ++++++++++++++++-- > -- > 1 file changed, 201 insertions(+), 53 deletions(-) > > diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c > b/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c > index 8aee30c759..7eee748958 100644 > --- a/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c > +++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c > @@ -14,6 +14,8 @@ > > #include "Partition.h" > > +#define MAX_CORRECTION_BLOCKS_NUM 512u > + > // > // C5BD4D42-1A76-4996-8956-73CDA326CD0A > // > @@ -48,61 +50,199 @@ UDF_DEVICE_PATH gUdfDevicePath = { > /** > Find the anchor volume descriptor pointer. > > - @param[in] BlockIo BlockIo interface. > - @param[in] DiskIo DiskIo interface. > - @param[out] AnchorPoint Anchor volume descriptor pointer. > + @param[in] BlockIo BlockIo interface. > + @param[in] DiskIo DiskIo interface. > + @param[out] AnchorPoint Anchor volume descriptor pointer. > + @param[out] LastRecordedBlock Last recorded block. > > - @retval EFI_SUCCESS Anchor volume descriptor pointer found. > - @retval EFI_VOLUME_CORRUPTED The file system structures are > corrupted. > - @retval other Anchor volume descriptor pointer not found. > + @retval EFI_SUCCESS Anchor volume descriptor pointer found. > + @retval EFI_VOLUME_CORRUPTED The file system structures are > corrupted. > + @retval other Anchor volume descriptor pointer not > found. > > **/ > EFI_STATUS > FindAnchorVolumeDescriptorPointer ( > IN EFI_BLOCK_IO_PROTOCOL *BlockIo, > IN EFI_DISK_IO_PROTOCOL *DiskIo, > - OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint > + OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint, > + OUT EFI_LBA *LastRecordedBlock > ) > { > - EFI_STATUS Status; > - UINT32 BlockSize; > - EFI_LBA EndLBA; > - EFI_LBA DescriptorLBAs[4]; > - UINTN Index; > - UDF_DESCRIPTOR_TAG *DescriptorTag; > + EFI_STATUS Status; > + UINT32 BlockSize; > + EFI_LBA EndLBA; > + UDF_DESCRIPTOR_TAG *DescriptorTag; > + UINTN AvdpsCount; > + UINTN Size; > + UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoints; > + INTN Index; > + UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPointPtr; > + EFI_LBA LastAvdpBlockNum; > > + // > + // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer > + // > + // An Anchor Volume Descriptor Pointer structure shall be recorded in at > + // least 2 of the following 3 locations on the media: Logical Sector 256, > + // N - 256 or N, where N is the last *addressable* sector of a volume. > + // > + // To figure out what logical sector N is, the SCSI commands READ CAPACITY > and > + // READ TRACK INFORMATION are used, however many drives or medias > report their > + // "last recorded block" wrongly. Although, READ CAPACITY returns the last > + // readable data block but there might be unwritten blocks, which are > located > + // outside any track and therefore AVDP will not be found at block N. > + // > + // That said, we define a magic number of 512 blocks to be used as > correction > + // when attempting to find AVDP and define last block number. > + // > BlockSize = BlockIo->Media->BlockSize; > EndLBA = BlockIo->Media->LastBlock; > - DescriptorLBAs[0] = 256; > - DescriptorLBAs[1] = EndLBA - 256; > - DescriptorLBAs[2] = EndLBA; > - DescriptorLBAs[3] = 512; > + *LastRecordedBlock = EndLBA; > + AvdpsCount = 0; > > - for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) { > - Status = DiskIo->ReadDisk ( > - DiskIo, > - BlockIo->Media->MediaId, > - MultU64x32 (DescriptorLBAs[Index], BlockSize), > - sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER), > - (VOID *)AnchorPoint > - ); > - if (EFI_ERROR (Status)) { > - return Status; > - } > + // > + // Find AVDP at block 256 > + // > + Status = DiskIo->ReadDisk ( > + DiskIo, > + BlockIo->Media->MediaId, > + MultU64x32 (256, BlockSize), > + sizeof (*AnchorPoint), > + AnchorPoint > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + DescriptorTag = &AnchorPoint->DescriptorTag; > + > + // > + // Check if read block is a valid AVDP descriptor > + // > + if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) { > + DEBUG ((DEBUG_INFO, "%a: found AVDP at block %d\n", __FUNCTION__, > 256)); > + AvdpsCount++; > + } > + > + // > + // Find AVDP at block N - 256 > + // > + Status = DiskIo->ReadDisk ( > + DiskIo, > + BlockIo->Media->MediaId, > + MultU64x32 ((UINT64)EndLBA - 256, BlockSize), > + sizeof (*AnchorPoint), > + AnchorPoint > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Check if read block is a valid AVDP descriptor > + // > + if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer && > + ++AvdpsCount == 2) { > + DEBUG ((DEBUG_INFO, "%a: found AVDP at block %Ld\n", __FUNCTION__, > + EndLBA - 256)); > + return EFI_SUCCESS; > + } > + > + // > + // Check if at least one AVDP was found in previous locations > + // > + if (AvdpsCount == 0) { > + return EFI_VOLUME_CORRUPTED; > + } > + > + // > + // Find AVDP at block N > + // > + Status = DiskIo->ReadDisk ( > + DiskIo, > + BlockIo->Media->MediaId, > + MultU64x32 ((UINT64)EndLBA, BlockSize), > + sizeof (*AnchorPoint), > + AnchorPoint > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Check if read block is a valid AVDP descriptor > + // > + if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) { > + return EFI_SUCCESS; > + } > + > + // > + // No AVDP found at block N. Possibly drive/media returned bad last > recorded > + // block, or it is part of unwritten data blocks and outside any track. > + // > + // Search backwards for an AVDP from block N-1 through > + // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct > last block > + // number for the new UDF partition child handle. > + // > + Size = MAX_CORRECTION_BLOCKS_NUM * BlockSize; > + > + AnchorPoints = AllocateZeroPool (Size); > + if (AnchorPoints == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks > + // > + Status = DiskIo->ReadDisk ( > + DiskIo, > + BlockIo->Media->MediaId, > + MultU64x32 ((UINT64)EndLBA - MAX_CORRECTION_BLOCKS_NUM, > BlockSize), > + Size, > + AnchorPoints > + ); > + if (EFI_ERROR (Status)) { > + goto Out_Free; > + } > > - DescriptorTag = &AnchorPoint->DescriptorTag; > + Status = EFI_VOLUME_CORRUPTED; > + > + // > + // Search for AVDP from blocks N-1 through N- > MAX_CORRECTION_BLOCKS_NUM > + // > + for (Index = MAX_CORRECTION_BLOCKS_NUM - 2; Index >= 0; Index--) { > + AnchorPointPtr = (VOID *)((UINTN)AnchorPoints + Index * BlockSize); > + > + DescriptorTag = &AnchorPointPtr->DescriptorTag; > > // > - // Check if read LBA has a valid AVDP descriptor. > + // Check if read block is a valid AVDP descriptor > // > if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) { > - return EFI_SUCCESS; > + // > + // Calculate last recorded block number > + // > + LastAvdpBlockNum = EndLBA - (MAX_CORRECTION_BLOCKS_NUM - > Index); > + DEBUG ((DEBUG_WARN, "%a: found AVDP at block %Ld\n", > __FUNCTION__, > + LastAvdpBlockNum)); > + DEBUG ((DEBUG_WARN, "%a: correcting last block from %Ld to %Ld\n", > + __FUNCTION__, EndLBA, LastAvdpBlockNum)); > + // > + // Save read AVDP from last block > + // > + CopyMem (AnchorPoint, AnchorPointPtr, sizeof (*AnchorPointPtr)); > + // > + // Set last recorded block number > + // > + *LastRecordedBlock = LastAvdpBlockNum; > + Status = EFI_SUCCESS; > + break; > } > } > - // > - // No AVDP found. > - // > - return EFI_VOLUME_CORRUPTED; > + > +Out_Free: > + FreePool (AnchorPoints); > + return Status; > } > > /** > @@ -280,16 +420,17 @@ IsLogicalVolumeDescriptorSupported ( > Find UDF logical volume location and whether it is supported by current > EDK2 > UDF file system implementation. > > - @param[in] BlockIo BlockIo interface. > - @param[in] DiskIo DiskIo interface. > - @param[in] AnchorPoint Anchor volume descriptor pointer. > - @param[out] MainVdsStartBlock Main VDS starting block number. > - @param[out] MainVdsEndBlock Main VDS ending block number. > + @param[in] BlockIo BlockIo interface. > + @param[in] DiskIo DiskIo interface. > + @param[in] AnchorPoint Anchor volume descriptor pointer. > + @param[in] LastRecordedBlock Last recorded block in media. > + @param[out] MainVdsStartBlock Main VDS starting block number. > + @param[out] MainVdsEndBlock Main VDS ending block number. > > - @retval EFI_SUCCESS UDF logical volume was found. > - @retval EFI_VOLUME_CORRUPTED UDF file system structures are > corrupted. > - @retval EFI_UNSUPPORTED UDF logical volume is not supported. > - @retval other Failed to perform disk I/O. > + @retval EFI_SUCCESS UDF logical volume was found. > + @retval EFI_VOLUME_CORRUPTED UDF file system structures are > corrupted. > + @retval EFI_UNSUPPORTED UDF logical volume is not supported. > + @retval other Failed to perform disk I/O. > > **/ > EFI_STATUS > @@ -297,13 +438,13 @@ FindLogicalVolumeLocation ( > IN EFI_BLOCK_IO_PROTOCOL *BlockIo, > IN EFI_DISK_IO_PROTOCOL *DiskIo, > IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint, > + IN EFI_LBA LastRecordedBlock, > OUT UINT64 *MainVdsStartBlock, > OUT UINT64 *MainVdsEndBlock > ) > { > EFI_STATUS Status; > UINT32 BlockSize; > - EFI_LBA LastBlock; > UDF_EXTENT_AD *ExtentAd; > UINT64 SeqBlocksNum; > UINT64 SeqStartBlock; > @@ -316,7 +457,6 @@ FindLogicalVolumeLocation ( > UDF_DESCRIPTOR_TAG *DescriptorTag; > > BlockSize = BlockIo->Media->BlockSize; > - LastBlock = BlockIo->Media->LastBlock; > ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent; > > // > @@ -328,7 +468,7 @@ FindLogicalVolumeLocation ( > // Also make sure it does not exceed maximum number of blocks in the disk. > // > SeqBlocksNum = DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize); > - if (SeqBlocksNum < 16 || (EFI_LBA)SeqBlocksNum > LastBlock + 1) { > + if (SeqBlocksNum < 16 || (EFI_LBA)SeqBlocksNum > LastRecordedBlock + 1) { > return EFI_VOLUME_CORRUPTED; > } > > @@ -336,8 +476,8 @@ FindLogicalVolumeLocation ( > // Check for valid Volume Descriptor Sequence starting block number > // > SeqStartBlock = (UINT64)ExtentAd->ExtentLocation; > - if (SeqStartBlock > LastBlock || > - SeqStartBlock + SeqBlocksNum - 1 > LastBlock) { > + if (SeqStartBlock > LastRecordedBlock || > + SeqStartBlock + SeqBlocksNum - 1 > LastRecordedBlock) { > return EFI_VOLUME_CORRUPTED; > } > > @@ -437,9 +577,10 @@ FindLogicalVolumeLocation ( > *MainVdsStartBlock = GuardMainVdsStartBlock; > // > // We do not need to read either LVD or PD descriptors to know the last > - // valid block in the found UDF file system. It's already LastBlock. > + // valid block in the found UDF file system. It's already > + // LastRecordedBlock. > // > - *MainVdsEndBlock = LastBlock; > + *MainVdsEndBlock = LastRecordedBlock; > > Status = EFI_SUCCESS; > } > @@ -473,8 +614,9 @@ FindUdfFileSystem ( > OUT EFI_LBA *EndingLBA > ) > { > - EFI_STATUS Status; > + EFI_STATUS Status; > UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint; > + EFI_LBA LastRecordedBlock; > > // > // Find UDF volume identifiers > @@ -487,7 +629,12 @@ FindUdfFileSystem ( > // > // Find Anchor Volume Descriptor Pointer > // > - Status = FindAnchorVolumeDescriptorPointer (BlockIo, DiskIo, &AnchorPoint); > + Status = FindAnchorVolumeDescriptorPointer ( > + BlockIo, > + DiskIo, > + &AnchorPoint, > + &LastRecordedBlock > + ); > if (EFI_ERROR (Status)) { > return Status; > } > @@ -499,6 +646,7 @@ FindUdfFileSystem ( > BlockIo, > DiskIo, > &AnchorPoint, > + LastRecordedBlock, > (UINT64 *)StartingLBA, > (UINT64 *)EndingLBA > ); > -- > 2.11.0 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel