|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
310c69 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
310c69 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
310c69 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
310c69 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
310c69 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
310c69 |
* GNU General Public License for more details.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
310c69 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
310c69 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
310c69 |
* 02110-1301, USA.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* $Id: //eng/uds-releases/jasper/src/uds/bufferedReader.c#5 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "bufferedReader.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "compiler.h"
|
|
Packit Service |
310c69 |
#include "ioFactory.h"
|
|
Packit Service |
310c69 |
#include "logger.h"
|
|
Packit Service |
310c69 |
#include "memoryAlloc.h"
|
|
Packit Service |
310c69 |
#include "numeric.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#ifndef __KERNEL__
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Define sector_t. The kernel really wants us to use it. The code becomes
|
|
Packit Service |
310c69 |
* ugly if we need to #ifdef every usage of sector_t. Note that the of #define
|
|
Packit Service |
310c69 |
* means that even if a user mode include typedefs sector_t, it will not affect
|
|
Packit Service |
310c69 |
* this module.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
#define sector_t uint64_t
|
|
Packit Service |
310c69 |
#endif
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
struct bufferedReader {
|
|
Packit Service |
310c69 |
#ifdef __KERNEL__
|
|
Packit Service |
310c69 |
// IOFactory owning the block device
|
|
Packit Service |
310c69 |
IOFactory *br_factory;
|
|
Packit Service |
310c69 |
// The dm_bufio_client to read from
|
|
Packit Service |
310c69 |
struct dm_bufio_client *br_client;
|
|
Packit Service |
310c69 |
// The current dm_buffer
|
|
Packit Service |
310c69 |
struct dm_buffer *br_buffer;
|
|
Packit Service |
310c69 |
// The number of blocks that can be read from
|
|
Packit Service |
310c69 |
sector_t br_limit;
|
|
Packit Service |
310c69 |
// Number of the current block
|
|
Packit Service |
310c69 |
sector_t br_blockNumber;
|
|
Packit Service |
310c69 |
#else
|
|
Packit Service |
310c69 |
// Region to read from
|
|
Packit Service |
310c69 |
IORegion *br_region;
|
|
Packit Service |
310c69 |
// Number of the current block
|
|
Packit Service |
310c69 |
uint64_t br_blockNumber;
|
|
Packit Service |
310c69 |
#endif
|
|
Packit Service |
310c69 |
// Start of the buffer
|
|
Packit Service |
310c69 |
byte *br_start;
|
|
Packit Service |
310c69 |
// End of the data read from the buffer
|
|
Packit Service |
310c69 |
byte *br_pointer;
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#ifdef __KERNEL__
|
|
Packit Service |
310c69 |
/*****************************************************************************/
|
|
Packit Service |
310c69 |
static void readAhead(BufferedReader *br, sector_t blockNumber)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (blockNumber < br->br_limit) {
|
|
Packit Service |
310c69 |
enum { MAX_READ_AHEAD = 4 };
|
|
Packit Service |
310c69 |
size_t readAhead = minSizeT(MAX_READ_AHEAD, br->br_limit - blockNumber);
|
|
Packit Service |
310c69 |
dm_bufio_prefetch(br->br_client, blockNumber, readAhead);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
#endif
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*****************************************************************************/
|
|
Packit Service |
310c69 |
#ifdef __KERNEL__
|
|
Packit Service |
310c69 |
int makeBufferedReader(IOFactory *factory,
|
|
Packit Service |
310c69 |
struct dm_bufio_client *client,
|
|
Packit Service |
310c69 |
sector_t blockLimit,
|
|
Packit Service |
310c69 |
BufferedReader **readerPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BufferedReader *reader = NULL;
|
|
Packit Service |
310c69 |
int result = ALLOCATE(1, BufferedReader, "buffered reader", &reader);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*reader = (BufferedReader) {
|
|
Packit Service |
310c69 |
.br_factory = factory,
|
|
Packit Service |
310c69 |
.br_client = client,
|
|
Packit Service |
310c69 |
.br_buffer = NULL,
|
|
Packit Service |
310c69 |
.br_limit = blockLimit,
|
|
Packit Service |
310c69 |
.br_blockNumber = 0,
|
|
Packit Service |
310c69 |
.br_start = NULL,
|
|
Packit Service |
310c69 |
.br_pointer = NULL,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
readAhead(reader,0);
|
|
Packit Service |
310c69 |
getIOFactory(factory);
|
|
Packit Service |
310c69 |
*readerPtr = reader;
|
|
Packit Service |
310c69 |
return UDS_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
#else
|
|
Packit Service |
310c69 |
int makeBufferedReader(IORegion *region, BufferedReader **readerPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
byte *data;
|
|
Packit Service |
310c69 |
int result = ALLOCATE_IO_ALIGNED(UDS_BLOCK_SIZE, byte,
|
|
Packit Service |
310c69 |
"buffer writer buffer", &data);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BufferedReader *reader = NULL;
|
|
Packit Service |
310c69 |
result = ALLOCATE(1, BufferedReader, "buffered reader", &reader);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
FREE(data);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*reader = (BufferedReader) {
|
|
Packit Service |
310c69 |
.br_region = region,
|
|
Packit Service |
310c69 |
.br_blockNumber = 0,
|
|
Packit Service |
310c69 |
.br_start = data,
|
|
Packit Service |
310c69 |
.br_pointer = NULL,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
getIORegion(region);
|
|
Packit Service |
310c69 |
*readerPtr = reader;
|
|
Packit Service |
310c69 |
return UDS_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
#endif
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*****************************************************************************/
|
|
Packit Service |
310c69 |
void freeBufferedReader(BufferedReader *br)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (br == NULL) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
#ifdef __KERNEL__
|
|
Packit Service |
310c69 |
if (br->br_buffer != NULL) {
|
|
Packit Service |
310c69 |
dm_bufio_release(br->br_buffer);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
dm_bufio_client_destroy(br->br_client);
|
|
Packit Service |
310c69 |
putIOFactory(br->br_factory);
|
|
Packit Service |
310c69 |
#else
|
|
Packit Service |
310c69 |
putIORegion(br->br_region);
|
|
Packit Service |
310c69 |
FREE(br->br_start);
|
|
Packit Service |
310c69 |
#endif
|
|
Packit Service |
310c69 |
FREE(br);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*****************************************************************************/
|
|
Packit Service |
310c69 |
static int positionReader(BufferedReader *br,
|
|
Packit Service |
310c69 |
sector_t blockNumber,
|
|
Packit Service |
310c69 |
off_t offset)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if ((br->br_pointer == NULL) || (blockNumber != br->br_blockNumber)) {
|
|
Packit Service |
310c69 |
#ifdef __KERNEL__
|
|
Packit Service |
310c69 |
if (blockNumber >= br->br_limit) {
|
|
Packit Service |
310c69 |
return UDS_OUT_OF_RANGE;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
if (br->br_buffer != NULL) {
|
|
Packit Service |
310c69 |
dm_bufio_release(br->br_buffer);
|
|
Packit Service |
310c69 |
br->br_buffer = NULL;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
struct dm_buffer *buffer = NULL;
|
|
Packit Service |
310c69 |
void *data = dm_bufio_read(br->br_client, blockNumber, &buffer);
|
|
Packit Service |
310c69 |
if (IS_ERR(data)) {
|
|
Packit Service |
310c69 |
return -PTR_ERR(data);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
br->br_buffer = buffer;
|
|
Packit Service |
310c69 |
br->br_start = data;
|
|
Packit Service |
310c69 |
if (blockNumber == br->br_blockNumber + 1) {
|
|
Packit Service |
310c69 |
readAhead(br, blockNumber + 1);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
#else
|
|
Packit Service |
310c69 |
int result = readFromRegion(br->br_region, blockNumber * UDS_BLOCK_SIZE,
|
|
Packit Service |
310c69 |
br->br_start, UDS_BLOCK_SIZE, NULL);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
logWarningWithStringError(result, "%s got readFromRegion error",
|
|
Packit Service |
310c69 |
__func__);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
#endif
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
br->br_blockNumber = blockNumber;
|
|
Packit Service |
310c69 |
br->br_pointer = br->br_start + offset;
|
|
Packit Service |
310c69 |
return UDS_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*****************************************************************************/
|
|
Packit Service |
310c69 |
static size_t bytesRemainingInReadBuffer(BufferedReader *br)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (br->br_pointer == NULL
|
|
Packit Service |
310c69 |
? 0
|
|
Packit Service |
310c69 |
: br->br_start + UDS_BLOCK_SIZE - br->br_pointer);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*****************************************************************************/
|
|
Packit Service |
310c69 |
int readFromBufferedReader(BufferedReader *br, void *data, size_t length)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
byte *dp = data;
|
|
Packit Service |
310c69 |
int result = UDS_SUCCESS;
|
|
Packit Service |
310c69 |
while (length > 0) {
|
|
Packit Service |
310c69 |
if (bytesRemainingInReadBuffer(br) == 0) {
|
|
Packit Service |
310c69 |
sector_t blockNumber = br->br_blockNumber;
|
|
Packit Service |
310c69 |
if (br->br_pointer != NULL) {
|
|
Packit Service |
310c69 |
++blockNumber;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
result = positionReader(br, blockNumber, 0);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
break;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
size_t avail = bytesRemainingInReadBuffer(br);
|
|
Packit Service |
310c69 |
size_t chunk = minSizeT(length, avail);
|
|
Packit Service |
310c69 |
memcpy(dp, br->br_pointer, chunk);
|
|
Packit Service |
310c69 |
length -= chunk;
|
|
Packit Service |
310c69 |
dp += chunk;
|
|
Packit Service |
310c69 |
br->br_pointer += chunk;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (((result == UDS_OUT_OF_RANGE) || (result == UDS_END_OF_FILE))
|
|
Packit Service |
310c69 |
&& (dp - (byte *) data > 0)) {
|
|
Packit Service |
310c69 |
result = UDS_SHORT_READ;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*****************************************************************************/
|
|
Packit Service |
310c69 |
int verifyBufferedData(BufferedReader *br,
|
|
Packit Service |
310c69 |
const void *value,
|
|
Packit Service |
310c69 |
size_t length)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
const byte *vp = value;
|
|
Packit Service |
310c69 |
sector_t startingBlockNumber = br->br_blockNumber;
|
|
Packit Service |
310c69 |
int startingOffset = br->br_pointer - br->br_start;
|
|
Packit Service |
310c69 |
while (length > 0) {
|
|
Packit Service |
310c69 |
if (bytesRemainingInReadBuffer(br) == 0) {
|
|
Packit Service |
310c69 |
sector_t blockNumber = br->br_blockNumber;
|
|
Packit Service |
310c69 |
if (br->br_pointer != NULL) {
|
|
Packit Service |
310c69 |
++blockNumber;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
int result = positionReader(br, blockNumber, 0);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
positionReader(br, startingBlockNumber, startingOffset);
|
|
Packit Service |
310c69 |
return UDS_CORRUPT_FILE;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
size_t avail = bytesRemainingInReadBuffer(br);
|
|
Packit Service |
310c69 |
size_t chunk = minSizeT(length, avail);
|
|
Packit Service |
310c69 |
if (memcmp(vp, br->br_pointer, chunk) != 0) {
|
|
Packit Service |
310c69 |
positionReader(br, startingBlockNumber, startingOffset);
|
|
Packit Service |
310c69 |
return UDS_CORRUPT_FILE;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
length -= chunk;
|
|
Packit Service |
310c69 |
vp += chunk;
|
|
Packit Service |
310c69 |
br->br_pointer += chunk;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return UDS_SUCCESS;
|
|
Packit Service |
310c69 |
}
|