Blame source/uds/bufferedReader.c

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
}