NetworkPkg: Remove a CopyMem to speed up the HTTP boot download.

This patch updates the HTTP boot driver to use the caller provided buffer
directly in identity transfer-coding mode, this could save one time CopyMem
operation to benefit the download performance.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Fu Siyuan <siyuan.fu@intel.com>
Reviewed-by: Zhang Lubo <lubo.zhang@intel.com>
Reviewed-by: Jiaxin Wu <jiaxin.wu@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19482 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Fu Siyuan 2015-12-23 06:54:52 +00:00 committed by sfu5
parent 06e5ae774e
commit 7552c24e76
1 changed files with 163 additions and 108 deletions

View File

@ -456,81 +456,6 @@ HttpBootCreateHttpIo (
return EFI_SUCCESS;
}
/**
Get the file content from cached data.
@param[in] Private The pointer to the driver's private data.
@param[in] Uri Uri of the file to be retrieved from cache.
@param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
code of EFI_SUCCESS, the amount of data transferred to
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
the size of Buffer required to retrieve the requested file.
@param[out] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
then the size of the requested file is returned in
BufferSize.
@retval EFI_SUCCESS Successfully created.
@retval Others Failed to create HttpIo.
**/
EFI_STATUS
HttpBootGetFileFromCache (
IN HTTP_BOOT_PRIVATE_DATA *Private,
IN CHAR16 *Uri,
IN OUT UINTN *BufferSize,
OUT UINT8 *Buffer
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Entry2;
HTTP_BOOT_CACHE_CONTENT *Cache;
HTTP_BOOT_ENTITY_DATA *EntityData;
UINTN CopyedSize;
if (Uri == NULL || BufferSize == 0 || Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
NET_LIST_FOR_EACH (Entry, &Private->CacheList) {
Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);
//
// Compare the URI to see whether we already have a cache for this file.
//
if ((Cache->RequestData != NULL) &&
(Cache->RequestData->Url != NULL) &&
(StrCmp (Uri, Cache->RequestData->Url) == 0))
{
//
// Hit cache, check buffer size.
//
if (*BufferSize < Cache->EntityLength) {
*BufferSize = Cache->EntityLength;
return EFI_BUFFER_TOO_SMALL;
}
//
// Fill data to buffer.
//
CopyedSize = 0;
NET_LIST_FOR_EACH (Entry2, &Cache->EntityDataList) {
EntityData = NET_LIST_USER_STRUCT (Entry2, HTTP_BOOT_ENTITY_DATA, Link);
if (*BufferSize > CopyedSize) {
CopyMem (
Buffer + CopyedSize,
EntityData->DataStart,
MIN (EntityData->DataLength, *BufferSize - CopyedSize)
);
CopyedSize += MIN (EntityData->DataLength, *BufferSize - CopyedSize);
}
}
*BufferSize = CopyedSize;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
Release all the resource of a cache item.
@ -609,6 +534,91 @@ HttpBootFreeCacheList (
}
}
/**
Get the file content from cached data.
@param[in] Private The pointer to the driver's private data.
@param[in] Uri Uri of the file to be retrieved from cache.
@param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return
code of EFI_SUCCESS, the amount of data transferred to
Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
the size of Buffer required to retrieve the requested file.
@param[out] Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
then the size of the requested file is returned in
BufferSize.
@retval EFI_SUCCESS Successfully created.
@retval Others Failed to create HttpIo.
**/
EFI_STATUS
HttpBootGetFileFromCache (
IN HTTP_BOOT_PRIVATE_DATA *Private,
IN CHAR16 *Uri,
IN OUT UINTN *BufferSize,
OUT UINT8 *Buffer
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Entry2;
HTTP_BOOT_CACHE_CONTENT *Cache;
HTTP_BOOT_ENTITY_DATA *EntityData;
UINTN CopyedSize;
if (Uri == NULL || BufferSize == 0 || Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Search file in the cache list, the cache entry will be released upon a successful
// match.
//
NET_LIST_FOR_EACH (Entry, &Private->CacheList) {
Cache = NET_LIST_USER_STRUCT (Entry, HTTP_BOOT_CACHE_CONTENT, Link);
//
// Compare the URI to see whether we already have a cache for this file.
//
if ((Cache->RequestData != NULL) &&
(Cache->RequestData->Url != NULL) &&
(StrCmp (Uri, Cache->RequestData->Url) == 0))
{
//
// Hit cache, check buffer size.
//
if (*BufferSize < Cache->EntityLength) {
*BufferSize = Cache->EntityLength;
return EFI_BUFFER_TOO_SMALL;
}
//
// Fill data to buffer.
//
CopyedSize = 0;
NET_LIST_FOR_EACH (Entry2, &Cache->EntityDataList) {
EntityData = NET_LIST_USER_STRUCT (Entry2, HTTP_BOOT_ENTITY_DATA, Link);
if (*BufferSize > CopyedSize) {
CopyMem (
Buffer + CopyedSize,
EntityData->DataStart,
MIN (EntityData->DataLength, *BufferSize - CopyedSize)
);
CopyedSize += MIN (EntityData->DataLength, *BufferSize - CopyedSize);
}
}
*BufferSize = CopyedSize;
//
// On success, free the cached data to release the memory resource.
//
RemoveEntryList (&Cache->Link);
HttpBootFreeCache (Cache);
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
A callback function to intercept events during message parser.
@ -719,6 +729,8 @@ HttpBootGetBootFile (
HTTP_BOOT_CACHE_CONTENT *Cache;
UINT8 *Block;
CHAR16 *Url;
BOOLEAN IdentityMode;
UINTN ReceivedSize;
ASSERT (Private != NULL);
ASSERT (Private->HttpCreated);
@ -921,51 +933,94 @@ HttpBootGetBootFile (
//
Block = NULL;
if (!HeaderOnly) {
//
// 3.4.1, check whether we are in identity transfer-coding.
//
ContentLength = 0;
Status = HttpGetEntityLength (Parser, &ContentLength);
if (!EFI_ERROR (Status)) {
IdentityMode = TRUE;
} else {
IdentityMode = FALSE;
}
//
// 3.4.2, start the message-body download, the identity and chunked transfer-coding
// is handled in different path here.
//
ZeroMem (&ResponseBody, sizeof (HTTP_IO_RESOPNSE_DATA));
while (!HttpIsMessageComplete (Parser)) {
if (IdentityMode) {
//
// Allocate a block to hold the message-body, if caller doesn't provide
// a buffer, the block will be cached and we will allocate a new one here.
// In identity transfer-coding there is no need to parse the message body,
// just download the message body to the user provided buffer directly.
//
if (Block == NULL || Context.BufferSize == 0) {
Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);
if (Block == NULL) {
Status = EFI_OUT_OF_RESOURCES;
ReceivedSize = 0;
while (ReceivedSize < ContentLength) {
ResponseBody.Body = (CHAR8*) Buffer + ReceivedSize;
ResponseBody.BodyLength = *BufferSize - ReceivedSize;
Status = HttpIoRecvResponse (
&Private->HttpIo,
FALSE,
&ResponseBody
);
if (EFI_ERROR (Status)) {
goto ERROR_6;
}
Context.NewBlock = TRUE;
Context.Block = Block;
} else {
Context.NewBlock = FALSE;
ReceivedSize += ResponseBody.BodyLength;
}
ResponseBody.Body = (CHAR8*) Block;
ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;
Status = HttpIoRecvResponse (
&Private->HttpIo,
FALSE,
&ResponseBody
);
if (EFI_ERROR (Status)) {
goto ERROR_6;
}
} else {
//
// Parse the new received block of the message-body, the block will be saved in cache.
// In "chunked" transfer-coding mode, so we need to parse the received
// data to get the real entity content.
//
Status = HttpParseMessageBody (
Parser,
ResponseBody.BodyLength,
ResponseBody.Body
);
if (EFI_ERROR (Status)) {
goto ERROR_6;
Block = NULL;
while (!HttpIsMessageComplete (Parser)) {
//
// Allocate a buffer in Block to hold the message-body.
// If caller provides a buffer, this Block will be reused in every HttpIoRecvResponse().
// Otherwise a buffer, the buffer in Block will be cached and we should allocate a new before
// every HttpIoRecvResponse().
//
if (Block == NULL || Context.BufferSize == 0) {
Block = AllocatePool (HTTP_BOOT_BLOCK_SIZE);
if (Block == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ERROR_6;
}
Context.NewBlock = TRUE;
Context.Block = Block;
} else {
Context.NewBlock = FALSE;
}
ResponseBody.Body = (CHAR8*) Block;
ResponseBody.BodyLength = HTTP_BOOT_BLOCK_SIZE;
Status = HttpIoRecvResponse (
&Private->HttpIo,
FALSE,
&ResponseBody
);
if (EFI_ERROR (Status)) {
goto ERROR_6;
}
//
// Parse the new received block of the message-body, the block will be saved in cache.
//
Status = HttpParseMessageBody (
Parser,
ResponseBody.BodyLength,
ResponseBody.Body
);
if (EFI_ERROR (Status)) {
goto ERROR_6;
}
}
}
}
//
// 3.5 Message-body receive & parse is completed, get the file size.
// 3.5 Message-body receive & parse is completed, we should be able to get the file size now.
//
Status = HttpGetEntityLength (Parser, &ContentLength);
if (EFI_ERROR (Status)) {