Reviewed-by: Wu Jiaxin <jiaxin...@intel.com> Thanks, Jiaxin
> -----Original Message----- > From: Li, Songpeng > Sent: Wednesday, January 9, 2019 4:42 PM > To: edk2-devel@lists.01.org > Cc: Carsey, Jaben <jaben.car...@intel.com>; Ni, Ray <ray...@intel.com>; > Wu, Jiaxin <jiaxin...@intel.com> > Subject: [PATCH v1] ShellPkg/TftpDynamicCommand: Change file writing > method in tftp > > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1433 > > Current logic of shell tftp download was writing file after tftp > download finished, when the file is large, it looks like the shell > tftp command hanged after download was finished. To improve > end-user experience, the solution is using split file writing > instead. > > This patch update the code to open and close file inside > DownloadFile(), and save each packet to file within callback > function CheckPacket(). > > Since AllocatePage() is no-longer needed, This patch can also > remove the memory limitation. The download file can be larger > than system free memory now. > > Cc: Jaben Carsey <jaben.car...@intel.com> > Cc: Ruiyu Ni <ruiyu...@intel.com> > Cc: Wu Jiaxin <jiaxin...@intel.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Songpeng Li <songpeng...@intel.com> > --- > ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c | 152 > +++++++++----------- > 1 file changed, 64 insertions(+), 88 deletions(-) > > diff --git a/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c > b/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c > index ed081b5bad7c..a53fe16f0683 100644 > --- a/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c > +++ b/ShellPkg/DynamicCommand/TftpDynamicCommand/Tftp.c > @@ -41,6 +41,12 @@ STATIC CONST CHAR16 mTftpProgressFrame[] = L"[ > // (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b' > STATIC CONST CHAR16 mTftpProgressDelete[] = > L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\ > b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; > > +// Local File Handle > +SHELL_FILE_HANDLE mFileHandle; > + > +// Path of the local file, Unicode encoded > +CONST CHAR16 *mLocalFilePath; > + > /** > Check and convert the UINT16 option values of the 'tftp' command > > @@ -166,9 +172,6 @@ GetFileSize ( > @param[in] FileSize Size of the file in number of bytes > @param[in] BlockSize Value of the TFTP blksize option > @param[in] WindowSize Value of the TFTP window size option > - @param[out] Data Address where to store the address of the > buffer > - where the data of the file were downloaded in > - case of success. > > @retval EFI_SUCCESS The file was downloaded. > @retval EFI_OUT_OF_RESOURCES A memory allocation failed. > @@ -184,8 +187,7 @@ DownloadFile ( > IN CONST CHAR8 *AsciiFilePath, > IN UINTN FileSize, > IN UINT16 BlockSize, > - IN UINT16 WindowSize, > - OUT VOID **Data > + IN UINT16 WindowSize > ); > > /** > @@ -287,7 +289,6 @@ RunTftp ( > CHAR8 *AsciiRemoteFilePath; > UINTN FilePathSize; > CONST CHAR16 *Walker; > - CONST CHAR16 *LocalFilePath; > EFI_MTFTP4_CONFIG_DATA Mtftp4ConfigData; > EFI_HANDLE *Handles; > UINTN HandleCount; > @@ -297,9 +298,7 @@ RunTftp ( > EFI_HANDLE Mtftp4ChildHandle; > EFI_MTFTP4_PROTOCOL *Mtftp4; > UINTN FileSize; > - UINTN DataSize; > VOID *Data; > - SHELL_FILE_HANDLE FileHandle; > UINT16 BlockSize; > UINT16 WindowSize; > > @@ -309,7 +308,6 @@ RunTftp ( > AsciiRemoteFilePath = NULL; > Handles = NULL; > FileSize = 0; > - DataSize = 0; > BlockSize = MTFTP_DEFAULT_BLKSIZE; > WindowSize = MTFTP_DEFAULT_WINDOWSIZE; > > @@ -385,7 +383,7 @@ RunTftp ( > UnicodeStrToAsciiStrS (RemoteFilePath, AsciiRemoteFilePath, FilePathSize); > > if (ParamCount == 4) { > - LocalFilePath = ShellCommandLineGetRawValue (CheckPackage, 3); > + mLocalFilePath = ShellCommandLineGetRawValue (CheckPackage, 3); > } else { > Walker = RemoteFilePath + StrLen (RemoteFilePath); > while ((--Walker) >= RemoteFilePath) { > @@ -394,7 +392,7 @@ RunTftp ( > break; > } > } > - LocalFilePath = Walker + 1; > + mLocalFilePath = Walker + 1; > } > > // > @@ -543,7 +541,7 @@ RunTftp ( > goto NextHandle; > } > > - Status = DownloadFile (Mtftp4, RemoteFilePath, AsciiRemoteFilePath, > FileSize, BlockSize, WindowSize, &Data); > + Status = DownloadFile (Mtftp4, RemoteFilePath, AsciiRemoteFilePath, > FileSize, BlockSize, WindowSize); > if (EFI_ERROR (Status)) { > ShellPrintHiiEx ( > -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD), > @@ -552,45 +550,8 @@ RunTftp ( > goto NextHandle; > } > > - DataSize = FileSize; > - > - if (!EFI_ERROR (ShellFileExists (LocalFilePath))) { > - ShellDeleteFileByName (LocalFilePath); > - } > - > - Status = ShellOpenFileByName ( > - LocalFilePath, > - &FileHandle, > - EFI_FILE_MODE_CREATE | > - EFI_FILE_MODE_WRITE | > - EFI_FILE_MODE_READ, > - 0 > - ); > - if (EFI_ERROR (Status)) { > - ShellPrintHiiEx ( > - -1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), > - mTftpHiiHandle, L"tftp", LocalFilePath > - ); > - goto NextHandle; > - } > - > - Status = ShellWriteFile (FileHandle, &FileSize, Data); > - if (!EFI_ERROR (Status)) { > - ShellStatus = SHELL_SUCCESS; > - } else { > - ShellPrintHiiEx ( > - -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_WRITE), > - mTftpHiiHandle, LocalFilePath, Status > - ); > - } > - ShellCloseFile (&FileHandle); > - > NextHandle: > > - if (Data != NULL) { > - gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)Data, > EFI_SIZE_TO_PAGES (DataSize)); > - } > - > CloseProtocolAndDestroyServiceChild ( > ControllerHandle, > &gEfiMtftp4ServiceBindingProtocolGuid, > @@ -912,9 +873,6 @@ Error : > @param[in] FileSize Size of the file in number of bytes > @param[in] BlockSize Value of the TFTP blksize option > @param[in] WindowSize Value of the TFTP window size option > - @param[out] Data Address where to store the address of the > buffer > - where the data of the file were downloaded in > - case of success. > > @retval EFI_SUCCESS The file was downloaded. > @retval EFI_OUT_OF_RESOURCES A memory allocation failed. > @@ -930,13 +888,10 @@ DownloadFile ( > IN CONST CHAR8 *AsciiFilePath, > IN UINTN FileSize, > IN UINT16 BlockSize, > - IN UINT16 WindowSize, > - OUT VOID **Data > + IN UINT16 WindowSize > ) > { > EFI_STATUS Status; > - EFI_PHYSICAL_ADDRESS PagesAddress; > - VOID *Buffer; > DOWNLOAD_CONTEXT *TftpContext; > EFI_MTFTP4_TOKEN Mtftp4Token; > UINT8 BlksizeBuf[10]; > @@ -944,22 +899,6 @@ DownloadFile ( > > ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN)); > > - // Downloaded file can be large. BS.AllocatePages() is more faster > - // than AllocatePool() and avoid fragmentation. > - // The downloaded file could be an EFI application. Marking the > - // allocated page as EfiBootServicesCode would allow to execute a > - // potential downloaded EFI application. > - Status = gBS->AllocatePages ( > - AllocateAnyPages, > - EfiBootServicesCode, > - EFI_SIZE_TO_PAGES (FileSize), > - &PagesAddress > - ); > - if (EFI_ERROR (Status)) { > - return Status; > - } > - > - Buffer = (VOID*)(UINTN)PagesAddress; > TftpContext = AllocatePool (sizeof (DOWNLOAD_CONTEXT)); > if (TftpContext == NULL) { > Status = EFI_OUT_OF_RESOURCES; > @@ -970,8 +909,6 @@ DownloadFile ( > TftpContext->LastReportedNbOfBytes = 0; > > Mtftp4Token.Filename = (UINT8*)AsciiFilePath; > - Mtftp4Token.BufferSize = FileSize; > - Mtftp4Token.Buffer = Buffer; > Mtftp4Token.CheckPacket = CheckPacket; > Mtftp4Token.Context = (VOID*)TftpContext; > Mtftp4Token.OptionCount = 0; > @@ -1000,14 +937,41 @@ DownloadFile ( > mTftpHiiHandle, FilePath > ); > > + // > + // OPEN FILE > + // > + if (!EFI_ERROR (ShellFileExists (mLocalFilePath))) { > + ShellDeleteFileByName (mLocalFilePath); > + } > + > + Status = ShellOpenFileByName ( > + mLocalFilePath, > + &mFileHandle, > + EFI_FILE_MODE_CREATE | > + EFI_FILE_MODE_WRITE | > + EFI_FILE_MODE_READ, > + 0 > + ); > + if (EFI_ERROR (Status)) { > + ShellPrintHiiEx ( > + -1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), > + mTftpHiiHandle, L"tftp", mLocalFilePath > + ); > + goto Error; > + } > + > Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token); > ShellPrintHiiEx ( > -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), > mTftpHiiHandle > ); > > -Error : > + // > + // CLOSE FILE > + // > + ShellCloseFile (&mFileHandle); > > +Error : > if (TftpContext != NULL) { > FreePool (TftpContext); > } > @@ -1016,14 +980,7 @@ Error : > FreePool (Mtftp4Token.OptionList); > } > > - if (EFI_ERROR (Status)) { > - gBS->FreePages (PagesAddress, EFI_SIZE_TO_PAGES (FileSize)); > - return Status; > - } > - > - *Data = Buffer; > - > - return EFI_SUCCESS; > + return Status; > } > > /** > @@ -1054,6 +1011,7 @@ CheckPacket ( > UINTN Index; > UINTN LastStep; > UINTN Step; > + UINTN DownloadLen; > EFI_STATUS Status; > > if ((NTOHS (Packet->OpCode)) != EFI_MTFTP4_OPCODE_DATA) { > @@ -1061,17 +1019,35 @@ CheckPacket ( > } > > Context = (DOWNLOAD_CONTEXT*)Token->Context; > - if (Context->DownloadedNbOfBytes == 0) { > - ShellPrintEx (-1, -1, L"%s 0 Kb", mTftpProgressFrame); > - } > > // > // The data in the packet are prepended with two UINT16 : > // . OpCode = EFI_MTFTP4_OPCODE_DATA > // . Block = the number of this block of data > // > - Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode) > - - sizeof (Packet->Data.Block); > + DownloadLen = (UINTN)PacketLen - sizeof (Packet->OpCode) - sizeof > (Packet->Data.Block); > + > + ShellSetFilePosition(mFileHandle, Context->DownloadedNbOfBytes); > + Status = ShellWriteFile (mFileHandle, &DownloadLen, Packet->Data.Data); > + if (EFI_ERROR (Status)) { > + if (Context->DownloadedNbOfBytes > 0) { > + ShellPrintHiiEx ( > + -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), > + mTftpHiiHandle > + ); > + } > + ShellPrintHiiEx ( > + -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_WRITE), > + mTftpHiiHandle, mLocalFilePath, Status > + ); > + return Status; > + } > + > + if (Context->DownloadedNbOfBytes == 0) { > + ShellPrintEx (-1, -1, L"%s 0 Kb", mTftpProgressFrame); > + } > + > + Context->DownloadedNbOfBytes += DownloadLen; > NbOfKb = Context->DownloadedNbOfBytes / 1024; > > Progress[0] = L'\0'; > -- > 2.18.0.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel