Blame source/uds/indexLayout.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/indexLayout.c#19 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "indexLayout.h"
Packit Service 310c69
Packit Service 310c69
#include "buffer.h"
Packit Service 310c69
#include "compiler.h"
Packit Service 310c69
#include "config.h"
Packit Service 310c69
#include "indexConfig.h"
Packit Service 310c69
#include "layoutRegion.h"
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "masterIndexOps.h"
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
#include "nonce.h"
Packit Service 310c69
#include "openChapter.h"
Packit Service 310c69
Packit Service 310c69
/*
Packit Service 310c69
 * Overall layout of an index on disk:
Packit Service 310c69
 *
Packit Service 310c69
 * The layout is divided into a number of fixed-size regions, the sizes of
Packit Service 310c69
 * which are computed when the index is created. Every header and region
Packit Service 310c69
 * begins on 4K block boundary. Save regions are further sub-divided into
Packit Service 310c69
 * regions of their own.
Packit Service 310c69
 *
Packit Service 310c69
 * Each region has a kind and an instance number. Some kinds only have one
Packit Service 310c69
 * instance and therefore use RL_SOLE_INSTANCE (-1) as the instance number.
Packit Service 310c69
 * The RL_KIND_INDEX uses instances to represent sub-indices, where used.
Packit Service 310c69
 * A save region can either hold a checkpoint or a clean shutdown (determined
Packit Service 310c69
 * by the type). The instances determine which available save slot is used.
Packit Service 310c69
 * The RL_KIND_MASTER_INDEX uses instances to record which zone is being saved.
Packit Service 310c69
 *
Packit Service 310c69
 *     +-+-+--------+--------+--------+-----+---  -+-+
Packit Service 310c69
 *     | | |   I N D E X   0      101, 0    | ...  | |
Packit Service 310c69
 *     |H|C+--------+--------+--------+-----+---  -+S|
Packit Service 310c69
 *     |D|f| Volume | Save   | Save   |     |      |e|
Packit Service 310c69
 *     |R|g| Region | Region | Region | ... | ...  |a|
Packit Service 310c69
 *     | | | 201 -1 | 202  0 | 202  1 |     |      |l|
Packit Service 310c69
 *     +-+-+--------+--------+--------+-----+---  -+-+
Packit Service 310c69
 *
Packit Service 310c69
 * The header contains the encoded regional layout table as well as
Packit Service 310c69
 * the saved index configuration record. The sub-index regions and their
Packit Service 310c69
 * subdivisions are maintained in the same table.
Packit Service 310c69
 *
Packit Service 310c69
 * There are at least two save regions per sub-index to preserve the old
Packit Service 310c69
 * state should the saving of a state be incomplete. They are used in
Packit Service 310c69
 * a round-robin fashion.
Packit Service 310c69
 *
Packit Service 310c69
 * Anatomy of a save region:
Packit Service 310c69
 *
Packit Service 310c69
 *     +-+-----+------+------+-----+   -+-----+
Packit Service 310c69
 *     |H| IPM | MI   | MI   |     |    | OC  |
Packit Service 310c69
 *     |D|     | zone | zone | ... |    |     |
Packit Service 310c69
 *     |R| 301 | 302  | 302  |     |    | 303 |
Packit Service 310c69
 *     | | -1  | 0    | 1    |     |    | -1  |
Packit Service 310c69
 *     +-+-----+------+------+-----+   -+-----+
Packit Service 310c69
 *
Packit Service 310c69
 * Every region header has a type (and version). In save regions,
Packit Service 310c69
 * the open chapter only appears in RL_TYPE_SAVE not RL_TYPE_CHECKPOINT,
Packit Service 310c69
 * although the same space is reserved for both.
Packit Service 310c69
 *
Packit Service 310c69
 * The header contains the encoded regional layout table as well as the
Packit Service 310c69
 * index state record for that save or checkpoint. Each save or checkpoint
Packit Service 310c69
 * has a unique generation number and nonce which is used to seed the
Packit Service 310c69
 * checksums of those regions.
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
typedef struct indexSaveData_v1 {
Packit Service 310c69
  uint64_t timestamp;           // ms since epoch...
Packit Service 310c69
  uint64_t nonce;
Packit Service 310c69
  uint32_t version;             // 1
Packit Service 310c69
  uint32_t unused__; 
Packit Service 310c69
} IndexSaveData;
Packit Service 310c69
Packit Service 310c69
typedef struct indexSaveLayout {
Packit Service 310c69
  LayoutRegion     indexSave;
Packit Service 310c69
  LayoutRegion     header;
Packit Service 310c69
  unsigned int     numZones;
Packit Service 310c69
  LayoutRegion     indexPageMap;
Packit Service 310c69
  LayoutRegion     freeSpace;
Packit Service 310c69
  LayoutRegion    *masterIndexZones;
Packit Service 310c69
  LayoutRegion    *openChapter;
Packit Service 310c69
  IndexSaveType    saveType;
Packit Service 310c69
  IndexSaveData    saveData;
Packit Service 310c69
  Buffer          *indexStateBuffer;
Packit Service 310c69
  bool             read;
Packit Service 310c69
  bool             written;
Packit Service 310c69
} IndexSaveLayout;
Packit Service 310c69
Packit Service 310c69
typedef struct subIndexLayout {
Packit Service 310c69
  LayoutRegion     subIndex;
Packit Service 310c69
  uint64_t         nonce;
Packit Service 310c69
  LayoutRegion     volume;
Packit Service 310c69
  IndexSaveLayout *saves;
Packit Service 310c69
} SubIndexLayout;
Packit Service 310c69
Packit Service 310c69
typedef struct superBlockData_v1 {
Packit Service 310c69
  byte     magicLabel[32];
Packit Service 310c69
  byte     nonceInfo[32];
Packit Service 310c69
  uint64_t nonce;
Packit Service 310c69
  uint32_t version;             // 2
Packit Service 310c69
  uint32_t blockSize;           // for verification
Packit Service 310c69
  uint16_t numIndexes;          // 1
Packit Service 310c69
  uint16_t maxSaves;
Packit Service 310c69
  uint64_t openChapterBlocks;
Packit Service 310c69
  uint64_t pageMapBlocks;
Packit Service 310c69
} SuperBlockData;
Packit Service 310c69
Packit Service 310c69
struct indexLayout {
Packit Service 310c69
  IOFactory            *factory;
Packit Service 310c69
  off_t                 offset;
Packit Service 310c69
  struct index_version  indexVersion;
Packit Service 310c69
  SuperBlockData        super;
Packit Service 310c69
  LayoutRegion          header;
Packit Service 310c69
  LayoutRegion          config;
Packit Service 310c69
  SubIndexLayout        index;
Packit Service 310c69
  LayoutRegion          seal;
Packit Service 310c69
  uint64_t              totalBlocks;
Packit Service 310c69
  int                   refCount;
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Structure used to compute single file layout sizes.
Packit Service 310c69
 *
Packit Service 310c69
 * Note that the masterIndexBlocks represent all zones and are sized for
Packit Service 310c69
 * the maximum number of blocks that would be needed regardless of the number
Packit Service 310c69
 * of zones (up to the maximum value) that are used at run time.
Packit Service 310c69
 *
Packit Service 310c69
 * Similarly, the number of saves is sized for the minimum safe value
Packit Service 310c69
 * assuming checkpointing is enabled, since that is also a run-time parameter.
Packit Service 310c69
 **/
Packit Service 310c69
typedef struct saveLayoutSizes {
Packit Service 310c69
  Configuration config;                 // this is a captive copy
Packit Service 310c69
  Geometry      geometry;               // this is a captive copy
Packit Service 310c69
  unsigned int  numSaves;               // per sub-index
Packit Service 310c69
  size_t        blockSize;              // in bytes
Packit Service 310c69
  uint64_t      volumeBlocks;           // per sub-index
Packit Service 310c69
  uint64_t      masterIndexBlocks;      // per save
Packit Service 310c69
  uint64_t      pageMapBlocks;          // per save
Packit Service 310c69
  uint64_t      openChapterBlocks;      // per save
Packit Service 310c69
  uint64_t      saveBlocks;             // per sub-index
Packit Service 310c69
  uint64_t      subIndexBlocks;         // per sub-index
Packit Service 310c69
  uint64_t      totalBlocks;            // for whole layout
Packit Service 310c69
} SaveLayoutSizes;
Packit Service 310c69
Packit Service 310c69
enum {
Packit Service 310c69
  INDEX_STATE_BUFFER_SIZE =  512,
Packit Service 310c69
  MAX_SAVES               =    5,
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
static const byte SINGLE_FILE_MAGIC_1[32] = "*ALBIREO*SINGLE*FILE*LAYOUT*001*";
Packit Service 310c69
enum {
Packit Service 310c69
  SINGLE_FILE_MAGIC_1_LENGTH = sizeof(SINGLE_FILE_MAGIC_1),
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
static int reconstituteSingleFileLayout(IndexLayout    *layout,
Packit Service 310c69
                                        SuperBlockData *super,
Packit Service 310c69
                                        RegionTable    *table,
Packit Service 310c69
                                        uint64_t        firstBlock)
Packit Service 310c69
  __attribute__((warn_unused_result));
Packit Service 310c69
static int writeIndexSaveLayout(IndexLayout *layout, IndexSaveLayout *isl)
Packit Service 310c69
  __attribute__((warn_unused_result));
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static INLINE uint64_t blockCount(uint64_t bytes, uint32_t blockSize)
Packit Service 310c69
{
Packit Service 310c69
  uint64_t blocks = bytes / blockSize;
Packit Service 310c69
  if (bytes % blockSize > 0) {
Packit Service 310c69
    ++blocks;
Packit Service 310c69
  }
Packit Service 310c69
  return blocks;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int computeSizes(SaveLayoutSizes        *sls,
Packit Service 310c69
                        const UdsConfiguration  config,
Packit Service 310c69
                        size_t                  blockSize,
Packit Service 310c69
                        unsigned int            numCheckpoints)
Packit Service 310c69
{
Packit Service 310c69
  if (config->bytesPerPage % blockSize != 0) {
Packit Service 310c69
    return logErrorWithStringError(UDS_INCORRECT_ALIGNMENT,
Packit Service 310c69
                                   "page size not a multiple of block size");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Configuration *cfg = NULL;
Packit Service 310c69
  int result = makeConfiguration(config, &cfg;;
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result, "cannot compute layout size");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  memset(sls, 0, sizeof(*sls));
Packit Service 310c69
Packit Service 310c69
  // internalize the configuration and geometry...
Packit Service 310c69
Packit Service 310c69
  sls->geometry        = *cfg->geometry;
Packit Service 310c69
  sls->config          = *cfg;
Packit Service 310c69
  sls->config.geometry = &sls->geometry;
Packit Service 310c69
Packit Service 310c69
  freeConfiguration(cfg);
Packit Service 310c69
Packit Service 310c69
  sls->numSaves         = 2 + numCheckpoints;
Packit Service 310c69
  sls->blockSize        = blockSize;
Packit Service 310c69
  sls->volumeBlocks     = sls->geometry.bytesPerVolume / blockSize;
Packit Service 310c69
Packit Service 310c69
  result = computeMasterIndexSaveBlocks(&sls->config, blockSize,
Packit Service 310c69
                                        &sls->masterIndexBlocks);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result, "cannot compute index save size");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  sls->pageMapBlocks =
Packit Service 310c69
    blockCount(computeIndexPageMapSaveSize(&sls->geometry), blockSize);
Packit Service 310c69
  sls->openChapterBlocks =
Packit Service 310c69
    blockCount(computeSavedOpenChapterSize(&sls->geometry), blockSize);
Packit Service 310c69
  sls->saveBlocks = 1 + (sls->masterIndexBlocks +
Packit Service 310c69
                         sls->pageMapBlocks + sls->openChapterBlocks);
Packit Service 310c69
  sls->subIndexBlocks = sls->volumeBlocks + (sls->numSaves * sls->saveBlocks);
Packit Service 310c69
  sls->totalBlocks = 3 + sls->subIndexBlocks;
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int udsComputeIndexSize(const UdsConfiguration  config,
Packit Service 310c69
                        unsigned int            numCheckpoints,
Packit Service 310c69
                        uint64_t               *indexSize)
Packit Service 310c69
{
Packit Service 310c69
  SaveLayoutSizes sizes;
Packit Service 310c69
  int result = computeSizes(&sizes, config, UDS_BLOCK_SIZE, numCheckpoints);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (indexSize != NULL) {
Packit Service 310c69
    *indexSize = sizes.totalBlocks * sizes.blockSize;
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int openLayoutReader(IndexLayout     *layout,
Packit Service 310c69
                            LayoutRegion    *lr,
Packit Service 310c69
                            BufferedReader **readerPtr)
Packit Service 310c69
{
Packit Service 310c69
  off_t start = lr->startBlock * layout->super.blockSize;
Packit Service 310c69
  size_t size = lr->numBlocks * layout->super.blockSize;
Packit Service 310c69
  return openBufferedReader(layout->factory, start, size, readerPtr);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int openLayoutWriter(IndexLayout     *layout,
Packit Service 310c69
                            LayoutRegion    *lr,
Packit Service 310c69
                            BufferedWriter **writerPtr)
Packit Service 310c69
{
Packit Service 310c69
  off_t start = lr->startBlock * layout->super.blockSize;
Packit Service 310c69
  size_t size = lr->numBlocks * layout->super.blockSize;
Packit Service 310c69
  return openBufferedWriter(layout->factory, start, size, writerPtr);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int decodeIndexSaveData(Buffer *buffer, IndexSaveData *saveData)
Packit Service 310c69
{
Packit Service 310c69
  int result = getUInt64LEFromBuffer(buffer, &saveData->timestamp);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt64LEFromBuffer(buffer, &saveData->nonce);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt32LEFromBuffer(buffer, &saveData->version);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt32LEFromBuffer(buffer, &saveData->unused__);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  // The unused padding has to be zeroed for correct nonce calculation
Packit Service 310c69
  if (saveData->unused__ != 0) {
Packit Service 310c69
    return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_LOG_ONLY(contentLength(buffer) == 0,
Packit Service 310c69
                           "%zu bytes decoded of %zu expected",
Packit Service 310c69
                           bufferLength(buffer), sizeof(*saveData));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
  }
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int decodeRegionHeader(Buffer *buffer, RegionHeader *header)
Packit Service 310c69
{
Packit Service 310c69
  int result = getUInt64LEFromBuffer(buffer, &header->magic);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt64LEFromBuffer(buffer, &header->regionBlocks);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt16LEFromBuffer(buffer, &header->type);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt16LEFromBuffer(buffer, &header->version);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt16LEFromBuffer(buffer, &header->numRegions);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt16LEFromBuffer(buffer, &header->payload);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_LOG_ONLY(contentLength(buffer) == 0,
Packit Service 310c69
                           "%zu bytes decoded of %zu expected",
Packit Service 310c69
                           bufferLength(buffer), sizeof(*header));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
  }
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int decodeLayoutRegion(Buffer *buffer, LayoutRegion *region)
Packit Service 310c69
{
Packit Service 310c69
  size_t cl1 = contentLength(buffer);
Packit Service 310c69
Packit Service 310c69
  int result = getUInt64LEFromBuffer(buffer, &region->startBlock);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt64LEFromBuffer(buffer, &region->numBlocks);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt32LEFromBuffer(buffer, &region->checksum);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt16LEFromBuffer(buffer, &region->kind);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt16LEFromBuffer(buffer, &region->instance);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_LOG_ONLY(cl1 - contentLength(buffer) == sizeof(*region),
Packit Service 310c69
                           "%zu bytes decoded, of %zu expected",
Packit Service 310c69
                           cl1 - contentLength(buffer), sizeof(*region));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
  }
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int loadRegionTable(BufferedReader *reader, RegionTable **tablePtr)
Packit Service 310c69
{
Packit Service 310c69
  Buffer *buffer;
Packit Service 310c69
  int result = makeBuffer(sizeof(RegionHeader), &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = readFromBufferedReader(reader, getBufferContents(buffer),
Packit Service 310c69
                                  bufferLength(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return logErrorWithStringError(result, "cannot read region table header");
Packit Service 310c69
  }
Packit Service 310c69
  result = resetBufferEnd(buffer, bufferLength(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  RegionHeader header;
Packit Service 310c69
  result = decodeRegionHeader(buffer, &header);
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  if (header.magic != REGION_MAGIC) {
Packit Service 310c69
    return UDS_NO_INDEX;
Packit Service 310c69
  }
Packit Service 310c69
  if (header.version != 1) {
Packit Service 310c69
    return logErrorWithStringError(UDS_UNSUPPORTED_VERSION,
Packit Service 310c69
                                   "unknown region table version %" PRIu16,
Packit Service 310c69
                                   header.version);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  RegionTable *table;
Packit Service 310c69
  result = ALLOCATE_EXTENDED(RegionTable, header.numRegions, LayoutRegion,
Packit Service 310c69
                             "single file layout region table", &table);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  table->header = header;
Packit Service 310c69
  result = makeBuffer(header.numRegions * sizeof(LayoutRegion), &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = readFromBufferedReader(reader, getBufferContents(buffer),
Packit Service 310c69
                                  bufferLength(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                   "cannot read region table layouts");
Packit Service 310c69
  }
Packit Service 310c69
  result = resetBufferEnd(buffer, bufferLength(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < header.numRegions; i++){
Packit Service 310c69
    result = decodeLayoutRegion(buffer, &table->regions[i]);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      FREE(table);
Packit Service 310c69
      freeBuffer(&buffer);
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  *tablePtr = table;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int decodeSuperBlockData(Buffer *buffer, SuperBlockData *super)
Packit Service 310c69
{
Packit Service 310c69
  int result = getBytesFromBuffer(buffer, 32, super->magicLabel);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getBytesFromBuffer(buffer, 32, super->nonceInfo);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt64LEFromBuffer(buffer, &super->nonce);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt32LEFromBuffer(buffer, &super->version);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt32LEFromBuffer(buffer, &super->blockSize);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt16LEFromBuffer(buffer, &super->numIndexes);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt16LEFromBuffer(buffer, &super->maxSaves);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = skipForward(buffer, 4);      // aligment
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt64LEFromBuffer(buffer, &super->openChapterBlocks);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt64LEFromBuffer(buffer, &super->pageMapBlocks);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_LOG_ONLY(contentLength(buffer) == 0,
Packit Service 310c69
                           "%zu bytes decoded of %zu expected",
Packit Service 310c69
                           bufferLength(buffer), sizeof(*super));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
  }
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int readSuperBlockData(BufferedReader *reader,
Packit Service 310c69
                              SuperBlockData *super,
Packit Service 310c69
                              size_t          savedSize)
Packit Service 310c69
{
Packit Service 310c69
  if (savedSize != sizeof(SuperBlockData)) {
Packit Service 310c69
    return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                   "unexpected super block data size %zu",
Packit Service 310c69
                                   savedSize);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (sizeof(super->magicLabel) != SINGLE_FILE_MAGIC_1_LENGTH) {
Packit Service 310c69
    return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                   "super block magic label size incorrect");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Buffer *buffer;
Packit Service 310c69
  int result = makeBuffer(savedSize, &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = readFromBufferedReader(reader, getBufferContents(buffer),
Packit Service 310c69
                                  bufferLength(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return logErrorWithStringError(result, "cannot read region table header");
Packit Service 310c69
  }
Packit Service 310c69
  result = resetBufferEnd(buffer, bufferLength(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = decodeSuperBlockData(buffer, super);
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result, "cannot read super block data");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (memcmp(super->magicLabel, SINGLE_FILE_MAGIC_1,
Packit Service 310c69
             SINGLE_FILE_MAGIC_1_LENGTH) != 0) {
Packit Service 310c69
    return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                   "unknown superblock magic label");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if ((super->version < SUPER_VERSION_MINIMUM)
Packit Service 310c69
      || (super->version > SUPER_VERSION_MAXIMUM)) {
Packit Service 310c69
    return logErrorWithStringError(UDS_UNSUPPORTED_VERSION,
Packit Service 310c69
                                   "unknown superblock version number %"
Packit Service 310c69
                                   PRIu32,
Packit Service 310c69
                                   super->version);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // We dropped the usage of multiple subindices before we ever ran UDS code in
Packit Service 310c69
  // the kernel.  We do not have code that will handle multiple subindices.
Packit Service 310c69
  if (super->numIndexes != 1) {
Packit Service 310c69
    return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                   "invalid subindex count %" PRIu32,
Packit Service 310c69
                                   super->numIndexes);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (generateMasterNonce(super->nonceInfo, sizeof(super->nonceInfo)) !=
Packit Service 310c69
      super->nonce)
Packit Service 310c69
  {
Packit Service 310c69
    return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                   "inconsistent superblock nonce");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int allocateSingleFileParts(IndexLayout    *layout,
Packit Service 310c69
                                   SuperBlockData *super)
Packit Service 310c69
{
Packit Service 310c69
  int result = ALLOCATE(super->maxSaves, IndexSaveLayout, __func__,
Packit Service 310c69
                        &layout->index.saves);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int loadSuperBlock(IndexLayout    *layout,
Packit Service 310c69
                          size_t          blockSize,
Packit Service 310c69
                          uint64_t        firstBlock,
Packit Service 310c69
                          BufferedReader *reader)
Packit Service 310c69
{
Packit Service 310c69
  RegionTable *table = NULL;
Packit Service 310c69
  int result = loadRegionTable(reader, &table);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (table->header.type != RH_TYPE_SUPER) {
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                   "not a superblock region table");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  SuperBlockData superBlockData;
Packit Service 310c69
  result = readSuperBlockData(reader, &superBlockData, table->header.payload);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    return logErrorWithStringError(result, "unknown superblock format");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (superBlockData.blockSize != blockSize) {
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    return logErrorWithStringError(UDS_WRONG_INDEX_CONFIG,
Packit Service 310c69
                                   "superblock saved blockSize %" PRIu32
Packit Service 310c69
                                   " differs from supplied blockSize %zu",
Packit Service 310c69
                                   superBlockData.blockSize, blockSize);
Packit Service 310c69
  }
Packit Service 310c69
  initializeIndexVersion(&layout->indexVersion, superBlockData.version);
Packit Service 310c69
Packit Service 310c69
  result = allocateSingleFileParts(layout, &superBlockData);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = reconstituteSingleFileLayout(layout, &superBlockData, table,
Packit Service 310c69
                                        firstBlock);
Packit Service 310c69
  FREE(table);
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int readIndexSaveData(BufferedReader  *reader,
Packit Service 310c69
                             IndexSaveData   *saveData,
Packit Service 310c69
                             size_t           savedSize,
Packit Service 310c69
                             Buffer         **bufferPtr)
Packit Service 310c69
{
Packit Service 310c69
  int result = UDS_SUCCESS;
Packit Service 310c69
  if (savedSize == 0) {
Packit Service 310c69
    memset(saveData, 0, sizeof(*saveData));
Packit Service 310c69
  } else {
Packit Service 310c69
    if (savedSize < sizeof(IndexSaveData)) {
Packit Service 310c69
      return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                     "unexpected index save data size %zu",
Packit Service 310c69
                                     savedSize);
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    Buffer *buffer;
Packit Service 310c69
    result = makeBuffer(sizeof(*saveData), &buffer);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
    result = readFromBufferedReader(reader, getBufferContents(buffer),
Packit Service 310c69
                                    bufferLength(buffer));
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      freeBuffer(&buffer);
Packit Service 310c69
      return logErrorWithStringError(result, "cannot read index save data");
Packit Service 310c69
    }
Packit Service 310c69
    result = resetBufferEnd(buffer, bufferLength(buffer));
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      freeBuffer(&buffer);
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    result = decodeIndexSaveData(buffer, saveData);
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    savedSize -= sizeof(IndexSaveData);
Packit Service 310c69
Packit Service 310c69
    if (saveData->version > 1) {
Packit Service 310c69
      return logErrorWithStringError(UDS_UNSUPPORTED_VERSION,
Packit Service 310c69
                                     "unkown index save verion number %"
Packit Service 310c69
                                     PRIu32,
Packit Service 310c69
                                     saveData->version);
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    if (savedSize > INDEX_STATE_BUFFER_SIZE) {
Packit Service 310c69
      return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                     "unexpected index state buffer size %zu",
Packit Service 310c69
                                     savedSize);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Buffer *buffer = NULL;
Packit Service 310c69
Packit Service 310c69
  if (saveData->version != 0) {
Packit Service 310c69
    result = makeBuffer(INDEX_STATE_BUFFER_SIZE, &buffer);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    if (savedSize > 0) {
Packit Service 310c69
      result = readFromBufferedReader(reader, getBufferContents(buffer),
Packit Service 310c69
                                      savedSize);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        freeBuffer(&buffer);
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
      result = resetBufferEnd(buffer, savedSize);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        freeBuffer(&buffer);
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  *bufferPtr = buffer;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
Packit Service 310c69
typedef struct {
Packit Service 310c69
  LayoutRegion  *nextRegion;
Packit Service 310c69
  LayoutRegion  *lastRegion;
Packit Service 310c69
  uint64_t       nextBlock;
Packit Service 310c69
  int            result;
Packit Service 310c69
} RegionIterator;
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((format(printf, 2, 3)))
Packit Service 310c69
static void iterError(RegionIterator *iter, const char *fmt, ...)
Packit Service 310c69
{
Packit Service 310c69
  va_list args;
Packit Service 310c69
  va_start(args, fmt);
Packit Service 310c69
  int r = vLogWithStringError(LOG_ERR, UDS_UNEXPECTED_RESULT, fmt, args);
Packit Service 310c69
  va_end(args);
Packit Service 310c69
  if (iter->result == UDS_SUCCESS) {
Packit Service 310c69
    iter->result = r;
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Set the next layout region in the layout according to a region table
Packit Service 310c69
 * iterator, unless the iterator already contains an error
Packit Service 310c69
 *
Packit Service 310c69
 * @param expect        whether to record an error or return false
Packit Service 310c69
 * @param lr            the layout region field to set
Packit Service 310c69
 * @param iter          the region iterator, which also holds the cumulative
Packit Service 310c69
 *                        result
Packit Service 310c69
 * @param numBlocks     if non-zero, the expected number of blocks
Packit Service 310c69
 * @param kind          the expected kind of the region
Packit Service 310c69
 * @param instance      the expected instance number of the region
Packit Service 310c69
 *
Packit Service 310c69
 * @return true if we meet expectations, false if we do not
Packit Service 310c69
 **/
Packit Service 310c69
static bool expectLayout(bool            expect,
Packit Service 310c69
                         LayoutRegion   *lr,
Packit Service 310c69
                         RegionIterator *iter,
Packit Service 310c69
                         uint64_t        numBlocks,
Packit Service 310c69
                         RegionKind      kind,
Packit Service 310c69
                         unsigned int    instance)
Packit Service 310c69
{
Packit Service 310c69
  if (iter->result != UDS_SUCCESS) {
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (iter->nextRegion == iter->lastRegion) {
Packit Service 310c69
    if (expect) {
Packit Service 310c69
      iterError(iter, "ran out of layout regions in region table");
Packit Service 310c69
    }
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (iter->nextRegion->startBlock != iter->nextBlock) {
Packit Service 310c69
    iterError(iter, "layout region not at expected offset");
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (iter->nextRegion->kind != kind) {
Packit Service 310c69
    if (expect) {
Packit Service 310c69
      iterError(iter, "layout region has incorrect kind");
Packit Service 310c69
    }
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (iter->nextRegion->instance != instance) {
Packit Service 310c69
    iterError(iter, "layout region has incorrect instance");
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (numBlocks > 0 && iter->nextRegion->numBlocks != numBlocks) {
Packit Service 310c69
    iterError(iter, "layout region size is incorrect");
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (lr != NULL) {
Packit Service 310c69
    *lr = *iter->nextRegion;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  iter->nextBlock += iter->nextRegion->numBlocks;
Packit Service 310c69
  iter->nextRegion++;
Packit Service 310c69
  return true;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static void setupLayout(LayoutRegion *lr,
Packit Service 310c69
                        uint64_t     *nextAddrPtr,
Packit Service 310c69
                        uint64_t      regionSize,
Packit Service 310c69
                        unsigned int  kind,
Packit Service 310c69
                        unsigned int  instance)
Packit Service 310c69
{
Packit Service 310c69
  *lr = (LayoutRegion) {
Packit Service 310c69
    .startBlock = *nextAddrPtr,
Packit Service 310c69
    .numBlocks  = regionSize,
Packit Service 310c69
    .checksum   = 0,
Packit Service 310c69
    .kind       = kind,
Packit Service 310c69
    .instance   = instance,
Packit Service 310c69
  };
Packit Service 310c69
  *nextAddrPtr += regionSize;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static void populateIndexSaveLayout(IndexSaveLayout *isl,
Packit Service 310c69
                                    SuperBlockData  *super,
Packit Service 310c69
                                    unsigned int     numZones,
Packit Service 310c69
                                    IndexSaveType    saveType)
Packit Service 310c69
{
Packit Service 310c69
  uint64_t nextBlock = isl->indexSave.startBlock;
Packit Service 310c69
Packit Service 310c69
  setupLayout(&isl->header, &nextBlock, 1, RL_KIND_HEADER, RL_SOLE_INSTANCE);
Packit Service 310c69
  setupLayout(&isl->indexPageMap, &nextBlock, super->pageMapBlocks,
Packit Service 310c69
              RL_KIND_INDEX_PAGE_MAP, RL_SOLE_INSTANCE);
Packit Service 310c69
Packit Service 310c69
  uint64_t blocksAvail = (isl->indexSave.numBlocks -
Packit Service 310c69
                          (nextBlock - isl->indexSave.startBlock) -
Packit Service 310c69
                          super->openChapterBlocks);
Packit Service 310c69
Packit Service 310c69
  if (numZones > 0) {
Packit Service 310c69
    uint64_t miBlockCount = blocksAvail / numZones;
Packit Service 310c69
    unsigned int z;
Packit Service 310c69
    for (z = 0; z < numZones; ++z) {
Packit Service 310c69
      LayoutRegion *miz = &isl->masterIndexZones[z];
Packit Service 310c69
      setupLayout(miz, &nextBlock, miBlockCount, RL_KIND_MASTER_INDEX, z);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  if (saveType == IS_SAVE && isl->openChapter != NULL) {
Packit Service 310c69
    setupLayout(isl->openChapter, &nextBlock, super->openChapterBlocks,
Packit Service 310c69
                RL_KIND_OPEN_CHAPTER, RL_SOLE_INSTANCE);
Packit Service 310c69
  }
Packit Service 310c69
  setupLayout(&isl->freeSpace, &nextBlock,
Packit Service 310c69
              (isl->indexSave.numBlocks -
Packit Service 310c69
               (nextBlock - isl->indexSave.startBlock)),
Packit Service 310c69
               RL_KIND_SCRATCH, RL_SOLE_INSTANCE);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int reconstructIndexSave(IndexSaveLayout *isl,
Packit Service 310c69
                                IndexSaveData   *saveData,
Packit Service 310c69
                                SuperBlockData  *super,
Packit Service 310c69
                                RegionTable     *table)
Packit Service 310c69
{
Packit Service 310c69
  isl->numZones = 0;
Packit Service 310c69
  isl->saveData = *saveData;
Packit Service 310c69
  isl->read     = false;
Packit Service 310c69
  isl->written  = false;
Packit Service 310c69
Packit Service 310c69
  if (table->header.type == RH_TYPE_SAVE) {
Packit Service 310c69
    isl->saveType = IS_SAVE;
Packit Service 310c69
  } else if (table->header.type == RH_TYPE_CHECKPOINT) {
Packit Service 310c69
    isl->saveType = IS_CHECKPOINT;
Packit Service 310c69
  } else {
Packit Service 310c69
    isl->saveType = NO_SAVE;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if ((table->header.numRegions == 0) ||
Packit Service 310c69
      ((table->header.numRegions == 1) &&
Packit Service 310c69
       (table->regions[0].kind == RL_KIND_SCRATCH)))
Packit Service 310c69
  {
Packit Service 310c69
    populateIndexSaveLayout(isl, super, 0, NO_SAVE);
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  RegionIterator iter = {
Packit Service 310c69
    .nextRegion = table->regions,
Packit Service 310c69
    .lastRegion = table->regions + table->header.numRegions,
Packit Service 310c69
    .nextBlock  = isl->indexSave.startBlock,
Packit Service 310c69
    .result     = UDS_SUCCESS,
Packit Service 310c69
  };
Packit Service 310c69
Packit Service 310c69
  expectLayout(true, &isl->header, &iter, 1, RL_KIND_HEADER, RL_SOLE_INSTANCE);
Packit Service 310c69
  expectLayout(true, &isl->indexPageMap, &iter, 0,
Packit Service 310c69
               RL_KIND_INDEX_PAGE_MAP, RL_SOLE_INSTANCE);
Packit Service 310c69
  unsigned int n = 0;
Packit Service 310c69
  RegionIterator tmpIter;
Packit Service 310c69
  for (tmpIter = iter;
Packit Service 310c69
       expectLayout(false, NULL, &tmpIter, 0, RL_KIND_MASTER_INDEX, n);
Packit Service 310c69
       ++n)
Packit Service 310c69
    ;
Packit Service 310c69
  isl->numZones = n;
Packit Service 310c69
Packit Service 310c69
  int result = UDS_SUCCESS;
Packit Service 310c69
Packit Service 310c69
  if (isl->numZones > 0) {
Packit Service 310c69
    result = ALLOCATE(n, LayoutRegion, "master index layout regions",
Packit Service 310c69
                      &isl->masterIndexZones);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (isl->saveType == IS_SAVE) {
Packit Service 310c69
    result = ALLOCATE(1, LayoutRegion, "open chapter layout region",
Packit Service 310c69
                      &isl->openChapter);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      FREE(isl->masterIndexZones);
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < isl->numZones; ++z) {
Packit Service 310c69
    expectLayout(true, &isl->masterIndexZones[z], &iter, 0,
Packit Service 310c69
                 RL_KIND_MASTER_INDEX, z);
Packit Service 310c69
  }
Packit Service 310c69
  if (isl->saveType == IS_SAVE) {
Packit Service 310c69
    expectLayout(true, isl->openChapter, &iter, 0,
Packit Service 310c69
                 RL_KIND_OPEN_CHAPTER, RL_SOLE_INSTANCE);
Packit Service 310c69
  }
Packit Service 310c69
  if (!expectLayout(false, &isl->freeSpace, &iter, 0,
Packit Service 310c69
                    RL_KIND_SCRATCH, RL_SOLE_INSTANCE))
Packit Service 310c69
  {
Packit Service 310c69
    isl->freeSpace = (LayoutRegion) {
Packit Service 310c69
      .startBlock = iter.nextBlock,
Packit Service 310c69
      .numBlocks  = (isl->indexSave.startBlock +
Packit Service 310c69
                     isl->indexSave.numBlocks) - iter.nextBlock,
Packit Service 310c69
      .checksum   = 0,
Packit Service 310c69
      .kind       = RL_KIND_SCRATCH,
Packit Service 310c69
      .instance   = RL_SOLE_INSTANCE,
Packit Service 310c69
    };
Packit Service 310c69
    iter.nextBlock = isl->freeSpace.startBlock + isl->freeSpace.numBlocks;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (iter.result != UDS_SUCCESS) {
Packit Service 310c69
    return iter.result;
Packit Service 310c69
  }
Packit Service 310c69
  if (iter.nextRegion != iter.lastRegion) {
Packit Service 310c69
    return logErrorWithStringError(UDS_UNEXPECTED_RESULT,
Packit Service 310c69
                                   "expected %ld additional regions",
Packit Service 310c69
                                   iter.lastRegion - iter.nextRegion);
Packit Service 310c69
  }
Packit Service 310c69
  if (iter.nextBlock != isl->indexSave.startBlock + isl->indexSave.numBlocks) {
Packit Service 310c69
    return logErrorWithStringError(UDS_UNEXPECTED_RESULT,
Packit Service 310c69
                                   "index save layout table incomplete");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int loadIndexSave(IndexSaveLayout *isl,
Packit Service 310c69
                         SuperBlockData  *super,
Packit Service 310c69
                         BufferedReader  *reader,
Packit Service 310c69
                         unsigned int     saveId)
Packit Service 310c69
{
Packit Service 310c69
  RegionTable *table = NULL;
Packit Service 310c69
  int result = loadRegionTable(reader, &table);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result,
Packit Service 310c69
                                   "cannot read index 0 save %u header",
Packit Service 310c69
                                   saveId);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (table->header.regionBlocks != isl->indexSave.numBlocks) {
Packit Service 310c69
    uint64_t regionBlocks = table->header.regionBlocks;
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                   "unexpected index 0 save %u "
Packit Service 310c69
                                   "region block count %llu",
Packit Service 310c69
                                   saveId, regionBlocks);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (table->header.type != RH_TYPE_SAVE &&
Packit Service 310c69
      table->header.type != RH_TYPE_CHECKPOINT &&
Packit Service 310c69
      table->header.type != RH_TYPE_UNSAVED)
Packit Service 310c69
  {
Packit Service 310c69
    unsigned int type = table->header.type;
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    return logErrorWithStringError(UDS_CORRUPT_COMPONENT, "unexpected"
Packit Service 310c69
                                   " index 0 save %u header type %u",
Packit Service 310c69
                                   saveId, type);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  IndexSaveData indexSaveData;
Packit Service 310c69
  result = readIndexSaveData(reader, &indexSaveData, table->header.payload,
Packit Service 310c69
                             &isl->indexStateBuffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    return logErrorWithStringError(result,
Packit Service 310c69
                                   "unknown index 0 save %u data format",
Packit Service 310c69
                                   saveId);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = reconstructIndexSave(isl, &indexSaveData, super, table);
Packit Service 310c69
  FREE(table);
Packit Service 310c69
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&isl->indexStateBuffer);
Packit Service 310c69
    return logErrorWithStringError(result,
Packit Service 310c69
                                   "cannot reconstruct index 0 save %u",
Packit Service 310c69
                                   saveId);
Packit Service 310c69
  }
Packit Service 310c69
  isl->read = true;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int loadSubIndexRegions(IndexLayout *layout)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int j;
Packit Service 310c69
  for (j = 0; j < layout->super.maxSaves; ++j) {
Packit Service 310c69
    IndexSaveLayout *isl = &layout->index.saves[j];
Packit Service 310c69
Packit Service 310c69
    BufferedReader *reader;
Packit Service 310c69
    int result = openLayoutReader(layout, &isl->indexSave, &reader);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      logErrorWithStringError(result, "cannot get reader for index 0 save %u",
Packit Service 310c69
                              j);
Packit Service 310c69
      while (j-- > 0) {
Packit Service 310c69
        IndexSaveLayout *isl = &layout->index.saves[j];
Packit Service 310c69
        FREE(isl->masterIndexZones);
Packit Service 310c69
        FREE(isl->openChapter);
Packit Service 310c69
        freeBuffer(&isl->indexStateBuffer);
Packit Service 310c69
      }
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    result = loadIndexSave(isl, &layout->super, reader, j);
Packit Service 310c69
    freeBufferedReader(reader);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      while (j-- > 0) {
Packit Service 310c69
        IndexSaveLayout *isl = &layout->index.saves[j];
Packit Service 310c69
        FREE(isl->masterIndexZones);
Packit Service 310c69
        FREE(isl->openChapter);
Packit Service 310c69
        freeBuffer(&isl->indexStateBuffer);
Packit Service 310c69
      }
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static int loadIndexLayout(IndexLayout *layout)
Packit Service 310c69
{
Packit Service 310c69
  BufferedReader *reader;
Packit Service 310c69
  int result = openBufferedReader(layout->factory, layout->offset,
Packit Service 310c69
                                  UDS_BLOCK_SIZE, &reader);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result, "unable to read superblock");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = loadSuperBlock(layout, UDS_BLOCK_SIZE,
Packit Service 310c69
                          layout->offset / UDS_BLOCK_SIZE, reader);
Packit Service 310c69
  freeBufferedReader(reader);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(layout->index.saves);
Packit Service 310c69
    layout->index.saves = NULL;
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = loadSubIndexRegions(layout);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(layout->index.saves);
Packit Service 310c69
    layout->index.saves = NULL;
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static void generateSuperBlockData(size_t          blockSize,
Packit Service 310c69
                                   unsigned int    maxSaves,
Packit Service 310c69
                                   uint64_t        openChapterBlocks,
Packit Service 310c69
                                   uint64_t        pageMapBlocks,
Packit Service 310c69
                                   SuperBlockData *super)
Packit Service 310c69
{
Packit Service 310c69
  memset(super, 0, sizeof(*super));
Packit Service 310c69
  memcpy(super->magicLabel, SINGLE_FILE_MAGIC_1, SINGLE_FILE_MAGIC_1_LENGTH);
Packit Service 310c69
  createUniqueNonceData(super->nonceInfo, sizeof(super->nonceInfo));
Packit Service 310c69
Packit Service 310c69
  super->nonce             = generateMasterNonce(super->nonceInfo,
Packit Service 310c69
                                                 sizeof(super->nonceInfo));
Packit Service 310c69
  super->version           = SUPER_VERSION_CURRENT;
Packit Service 310c69
  super->blockSize         = blockSize;
Packit Service 310c69
  super->numIndexes        = 1;
Packit Service 310c69
  super->maxSaves          = maxSaves;
Packit Service 310c69
  super->openChapterBlocks = openChapterBlocks;
Packit Service 310c69
  super->pageMapBlocks     = pageMapBlocks;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int resetIndexSaveLayout(IndexSaveLayout *isl,
Packit Service 310c69
                                uint64_t        *nextBlockPtr,
Packit Service 310c69
                                uint64_t         saveBlocks,
Packit Service 310c69
                                uint64_t         pageMapBlocks,
Packit Service 310c69
                                unsigned int     instance)
Packit Service 310c69
{
Packit Service 310c69
  uint64_t startBlock = *nextBlockPtr;
Packit Service 310c69
Packit Service 310c69
  if (isl->masterIndexZones) {
Packit Service 310c69
    FREE(isl->masterIndexZones);
Packit Service 310c69
  }
Packit Service 310c69
  if (isl->openChapter) {
Packit Service 310c69
    FREE(isl->openChapter);
Packit Service 310c69
  }
Packit Service 310c69
  if (isl->indexStateBuffer) {
Packit Service 310c69
    freeBuffer(&isl->indexStateBuffer);
Packit Service 310c69
  }
Packit Service 310c69
  memset(isl, 0, sizeof(*isl));
Packit Service 310c69
  isl->saveType = NO_SAVE;
Packit Service 310c69
  setupLayout(&isl->indexSave, &startBlock, saveBlocks, RL_KIND_SAVE,
Packit Service 310c69
              instance);
Packit Service 310c69
  setupLayout(&isl->header, nextBlockPtr,  1, RL_KIND_HEADER,
Packit Service 310c69
              RL_SOLE_INSTANCE);
Packit Service 310c69
  setupLayout(&isl->indexPageMap, nextBlockPtr, pageMapBlocks,
Packit Service 310c69
              RL_KIND_INDEX_PAGE_MAP, RL_SOLE_INSTANCE);
Packit Service 310c69
  uint64_t remaining = startBlock - *nextBlockPtr;
Packit Service 310c69
  setupLayout(&isl->freeSpace, nextBlockPtr, remaining, RL_KIND_SCRATCH,
Packit Service 310c69
              RL_SOLE_INSTANCE);
Packit Service 310c69
  // number of zones is a save-time parameter
Packit Service 310c69
  // presence of open chapter is a save-time parameter
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static void defineSubIndexNonce(SubIndexLayout *sil,
Packit Service 310c69
                                uint64_t        masterNonce,
Packit Service 310c69
                                unsigned int    indexId)
Packit Service 310c69
{
Packit Service 310c69
  struct subIndexNonceData {
Packit Service 310c69
    uint64_t offset;
Packit Service 310c69
    uint16_t indexId;
Packit Service 310c69
  };
Packit Service 310c69
  byte buffer[sizeof(struct subIndexNonceData)] = { 0 };
Packit Service 310c69
  size_t offset = 0;
Packit Service 310c69
  encodeUInt64LE(buffer, &offset, sil->subIndex.startBlock);
Packit Service 310c69
  encodeUInt16LE(buffer, &offset, indexId);
Packit Service 310c69
  sil->nonce = generateSecondaryNonce(masterNonce, buffer, sizeof(buffer));
Packit Service 310c69
  if (sil->nonce == 0) {
Packit Service 310c69
    sil->nonce = generateSecondaryNonce(~masterNonce + 1,
Packit Service 310c69
                                        buffer, sizeof(buffer));
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int setupSubIndex(SubIndexLayout  *sil,
Packit Service 310c69
                         uint64_t        *nextBlockPtr,
Packit Service 310c69
                         SaveLayoutSizes *sls,
Packit Service 310c69
                         unsigned int     instance,
Packit Service 310c69
                         uint64_t         masterNonce)
Packit Service 310c69
{
Packit Service 310c69
  uint64_t startBlock = *nextBlockPtr;
Packit Service 310c69
Packit Service 310c69
  setupLayout(&sil->subIndex, &startBlock, sls->subIndexBlocks,
Packit Service 310c69
              RL_KIND_INDEX, instance);
Packit Service 310c69
  setupLayout(&sil->volume, nextBlockPtr, sls->volumeBlocks,
Packit Service 310c69
              RL_KIND_VOLUME, RL_SOLE_INSTANCE);
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < sls->numSaves; ++i) {
Packit Service 310c69
    int result = resetIndexSaveLayout(&sil->saves[i], nextBlockPtr,
Packit Service 310c69
                                      sls->saveBlocks, sls->pageMapBlocks, i);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (startBlock != *nextBlockPtr) {
Packit Service 310c69
    return logErrorWithStringError(UDS_UNEXPECTED_RESULT,
Packit Service 310c69
                                   "sub index layout regions don't agree");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  defineSubIndexNonce(sil, masterNonce, instance);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
/**
Packit Service 310c69
 * Initialize a single file layout using the save layout sizes specified.
Packit Service 310c69
 *
Packit Service 310c69
 * @param layout  the layout to initialize
Packit Service 310c69
 * @param offset  the offset in bytes from the start of the backing storage
Packit Service 310c69
 * @param size    the size in bytes of the backing storage
Packit Service 310c69
 * @param sls     a populated SaveLayoutSizes object
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code, potentially
Packit Service 310c69
 *         UDS_INSUFFICIENT_INDEX_SPACE if the size of the backing store
Packit Service 310c69
 *              is not sufficient for the index configuration,
Packit Service 310c69
 *         UDS_BAD_INDEX_ALIGNMENT if the offset specified does not
Packit Service 310c69
 *              align properly with the index block and page sizes]
Packit Service 310c69
 *         various other errors
Packit Service 310c69
 **/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int initSingleFileLayout(IndexLayout     *layout,
Packit Service 310c69
                                uint64_t         offset,
Packit Service 310c69
                                uint64_t         size,
Packit Service 310c69
                                SaveLayoutSizes *sls)
Packit Service 310c69
{
Packit Service 310c69
  layout->totalBlocks = sls->totalBlocks;
Packit Service 310c69
Packit Service 310c69
  if (size < sls->totalBlocks * sls->blockSize) {
Packit Service 310c69
    return logErrorWithStringError(UDS_INSUFFICIENT_INDEX_SPACE,
Packit Service 310c69
                                   "not enough space for index as configured");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  generateSuperBlockData(sls->blockSize, sls->numSaves, sls->openChapterBlocks,
Packit Service 310c69
                         sls->pageMapBlocks, &layout->super);
Packit Service 310c69
  initializeIndexVersion(&layout->indexVersion, SUPER_VERSION_CURRENT);
Packit Service 310c69
Packit Service 310c69
  int result = allocateSingleFileParts(layout, &layout->super);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  uint64_t nextBlock = offset / sls->blockSize;
Packit Service 310c69
Packit Service 310c69
  setupLayout(&layout->header, &nextBlock, 1, RL_KIND_HEADER,
Packit Service 310c69
              RL_SOLE_INSTANCE);
Packit Service 310c69
  setupLayout(&layout->config, &nextBlock, 1, RL_KIND_CONFIG,
Packit Service 310c69
              RL_SOLE_INSTANCE);
Packit Service 310c69
  result = setupSubIndex(&layout->index, &nextBlock, sls, 0,
Packit Service 310c69
                         layout->super.nonce);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  setupLayout(&layout->seal, &nextBlock, 1, RL_KIND_SEAL, RL_SOLE_INSTANCE);
Packit Service 310c69
  if (nextBlock * sls->blockSize > offset + size) {
Packit Service 310c69
    return logErrorWithStringError(UDS_UNEXPECTED_RESULT,
Packit Service 310c69
                                   "layout does not fit as expected");
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static void expectSubIndex(SubIndexLayout *sil,
Packit Service 310c69
                           RegionIterator *iter,
Packit Service 310c69
                           SuperBlockData *super,
Packit Service 310c69
                           unsigned int    instance)
Packit Service 310c69
{
Packit Service 310c69
  if (iter->result != UDS_SUCCESS) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  uint64_t startBlock = iter->nextBlock;
Packit Service 310c69
Packit Service 310c69
  expectLayout(true, &sil->subIndex, iter, 0, RL_KIND_INDEX, instance);
Packit Service 310c69
Packit Service 310c69
  uint64_t endBlock = iter->nextBlock;
Packit Service 310c69
  iter->nextBlock = startBlock;
Packit Service 310c69
Packit Service 310c69
  expectLayout(true, &sil->volume, iter, 0, RL_KIND_VOLUME, RL_SOLE_INSTANCE);
Packit Service 310c69
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < super->maxSaves; ++i) {
Packit Service 310c69
    IndexSaveLayout *isl = &sil->saves[i];
Packit Service 310c69
    expectLayout(true, &isl->indexSave, iter, 0, RL_KIND_SAVE, i);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (iter->nextBlock != endBlock) {
Packit Service 310c69
    iterError(iter, "sub index region does not span all saves");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  defineSubIndexNonce(sil, super->nonce, instance);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Initialize a single file layout from the region table and super block data
Packit Service 310c69
 * stored in stable storage.
Packit Service 310c69
 *
Packit Service 310c69
 * @param layout      the layout to initialize
Packit Service 310c69
 * @param region      the IO region for this layout
Packit Service 310c69
 * @param super       the super block data read from the superblock
Packit Service 310c69
 * @param table       the region table read from the superblock
Packit Service 310c69
 * @param firstBlock  the first block number in the region
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int reconstituteSingleFileLayout(IndexLayout    *layout,
Packit Service 310c69
                                        SuperBlockData *super,
Packit Service 310c69
                                        RegionTable    *table,
Packit Service 310c69
                                        uint64_t        firstBlock)
Packit Service 310c69
{
Packit Service 310c69
  layout->super       = *super;
Packit Service 310c69
  layout->totalBlocks = table->header.regionBlocks;
Packit Service 310c69
Packit Service 310c69
  RegionIterator iter = {
Packit Service 310c69
    .nextRegion = table->regions,
Packit Service 310c69
    .lastRegion = table->regions + table->header.numRegions,
Packit Service 310c69
    .nextBlock  = firstBlock,
Packit Service 310c69
    .result     = UDS_SUCCESS
Packit Service 310c69
  };
Packit Service 310c69
Packit Service 310c69
  expectLayout(true, &layout->header, &iter, 1, RL_KIND_HEADER,
Packit Service 310c69
               RL_SOLE_INSTANCE);
Packit Service 310c69
  expectLayout(true, &layout->config, &iter, 1, RL_KIND_CONFIG,
Packit Service 310c69
               RL_SOLE_INSTANCE);
Packit Service 310c69
  expectSubIndex(&layout->index, &iter, &layout->super, 0);
Packit Service 310c69
  expectLayout(true, &layout->seal, &iter, 1, RL_KIND_SEAL, RL_SOLE_INSTANCE);
Packit Service 310c69
Packit Service 310c69
  if (iter.result != UDS_SUCCESS) {
Packit Service 310c69
    return iter.result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (iter.nextBlock != firstBlock + layout->totalBlocks) {
Packit Service 310c69
    return logErrorWithStringError(UDS_UNEXPECTED_RESULT,
Packit Service 310c69
                                   "layout table does not span total blocks");
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int saveSubIndexRegions(IndexLayout *layout)
Packit Service 310c69
{
Packit Service 310c69
  SubIndexLayout *sil = &layout->index;
Packit Service 310c69
  unsigned int j;
Packit Service 310c69
  for (j = 0; j < layout->super.maxSaves; ++j) {
Packit Service 310c69
    IndexSaveLayout *isl = &sil->saves[j];
Packit Service 310c69
    int result = writeIndexSaveLayout(layout, isl);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return logErrorWithStringError(result,
Packit Service 310c69
                                     "unable to format index %u save 0 layout",
Packit Service 310c69
                                     j);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int makeSingleFileRegionTable(IndexLayout   *layout,
Packit Service 310c69
                                     unsigned int  *numRegionsPtr,
Packit Service 310c69
                                     RegionTable  **tablePtr)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int numRegions =
Packit Service 310c69
    1 +                      // header
Packit Service 310c69
    1 +                      // config
Packit Service 310c69
    1 +                      // index
Packit Service 310c69
    1 +                      // volume
Packit Service 310c69
    layout->super.maxSaves + // saves
Packit Service 310c69
    1;                       // seal
Packit Service 310c69
Packit Service 310c69
  RegionTable *table;
Packit Service 310c69
  int result = ALLOCATE_EXTENDED(RegionTable, numRegions, LayoutRegion,
Packit Service 310c69
                                 "layout region table", &table);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  LayoutRegion *lr = &table->regions[0];
Packit Service 310c69
  *lr++ = layout->header;
Packit Service 310c69
  *lr++ = layout->config;
Packit Service 310c69
  SubIndexLayout *sil = &layout->index;
Packit Service 310c69
  *lr++ = sil->subIndex;
Packit Service 310c69
  *lr++ = sil->volume;
Packit Service 310c69
  unsigned int j;
Packit Service 310c69
  for (j = 0; j < layout->super.maxSaves; ++j) {
Packit Service 310c69
    *lr++ = sil->saves[j].indexSave;
Packit Service 310c69
  }
Packit Service 310c69
  *lr++ = layout->seal;
Packit Service 310c69
Packit Service 310c69
  result = ASSERT((lr == &table->regions[numRegions]),
Packit Service 310c69
                  "incorrect number of regions");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  *numRegionsPtr = numRegions;
Packit Service 310c69
  *tablePtr      = table;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int encodeIndexSaveData(Buffer *buffer, IndexSaveData *saveData)
Packit Service 310c69
{
Packit Service 310c69
  int result = putUInt64LEIntoBuffer(buffer, saveData->timestamp);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt64LEIntoBuffer(buffer, saveData->nonce);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt32LEIntoBuffer(buffer, saveData->version);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = zeroBytes(buffer, 4);        /* padding */
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_LOG_ONLY(contentLength(buffer) == sizeof *saveData,
Packit Service 310c69
                           "%zu bytes encoded of %zu expected",
Packit Service 310c69
                           contentLength(buffer), sizeof(*saveData));
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int encodeRegionHeader(Buffer *buffer, RegionHeader *header)
Packit Service 310c69
{
Packit Service 310c69
  size_t startingLength = contentLength(buffer);
Packit Service 310c69
  int result = putUInt64LEIntoBuffer(buffer, REGION_MAGIC);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt64LEIntoBuffer(buffer, header->regionBlocks);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt16LEIntoBuffer(buffer, header->type);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt16LEIntoBuffer(buffer, header->version);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt16LEIntoBuffer(buffer, header->numRegions);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt16LEIntoBuffer(buffer, header->payload);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result
Packit Service 310c69
    = ASSERT_LOG_ONLY(contentLength(buffer) - startingLength == sizeof(*header),
Packit Service 310c69
                      "%zu bytes encoded, of %zu expected",
Packit Service 310c69
                      contentLength(buffer) - startingLength, sizeof(*header));
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int encodeLayoutRegion(Buffer *buffer, LayoutRegion *region)
Packit Service 310c69
{
Packit Service 310c69
  size_t startingLength = contentLength(buffer);
Packit Service 310c69
  int result = putUInt64LEIntoBuffer(buffer, region->startBlock);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt64LEIntoBuffer(buffer, region->numBlocks);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt32LEIntoBuffer(buffer, region->checksum);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt16LEIntoBuffer(buffer, region->kind);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt16LEIntoBuffer(buffer, region->instance);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result
Packit Service 310c69
    = ASSERT_LOG_ONLY(contentLength(buffer) - startingLength == sizeof(*region),
Packit Service 310c69
                      "%zu bytes encoded, of %zu expected",
Packit Service 310c69
                      contentLength(buffer) - startingLength, sizeof(*region));
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int encodeSuperBlockData(Buffer *buffer, SuperBlockData *super)
Packit Service 310c69
{
Packit Service 310c69
  int result = putBytes(buffer, 32, &super->magicLabel);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putBytes(buffer, 32, &super->nonceInfo);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt64LEIntoBuffer(buffer, super->nonce);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt32LEIntoBuffer(buffer, super->version);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt32LEIntoBuffer(buffer, super->blockSize);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt16LEIntoBuffer(buffer, super->numIndexes);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt16LEIntoBuffer(buffer, super->maxSaves);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = zeroBytes(buffer, 4);      // aligment
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt64LEIntoBuffer(buffer, super->openChapterBlocks);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt64LEIntoBuffer(buffer, super->pageMapBlocks);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_LOG_ONLY(contentLength(buffer) == sizeof(SuperBlockData),
Packit Service 310c69
                           "%zu bytes encoded, of %zu expected",
Packit Service 310c69
                           contentLength(buffer), sizeof(SuperBlockData));
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int writeSingleFileHeader(IndexLayout    *layout,
Packit Service 310c69
                                 RegionTable    *table,
Packit Service 310c69
                                 unsigned int    numRegions,
Packit Service 310c69
                                 BufferedWriter *writer)
Packit Service 310c69
{
Packit Service 310c69
  table->header = (RegionHeader) {
Packit Service 310c69
    .magic        = REGION_MAGIC,
Packit Service 310c69
    .regionBlocks = layout->totalBlocks,
Packit Service 310c69
    .type         = RH_TYPE_SUPER,
Packit Service 310c69
    .version      = 1,
Packit Service 310c69
    .numRegions   = numRegions,
Packit Service 310c69
    .payload      = sizeof(layout->super),
Packit Service 310c69
  };
Packit Service 310c69
Packit Service 310c69
  size_t tableSize = sizeof(RegionTable) + numRegions * sizeof(LayoutRegion);
Packit Service 310c69
Packit Service 310c69
  Buffer *buffer;
Packit Service 310c69
  int result = makeBuffer(tableSize, &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = encodeRegionHeader(buffer, &table->header);
Packit Service 310c69
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < numRegions; i++) {
Packit Service 310c69
    if (result == UDS_SUCCESS) {
Packit Service 310c69
      result = encodeLayoutRegion(buffer, &table->regions[i]);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (result == UDS_SUCCESS) {
Packit Service 310c69
    result = writeToBufferedWriter(writer,  getBufferContents(buffer),
Packit Service 310c69
                                   contentLength(buffer));
Packit Service 310c69
  }
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = makeBuffer(sizeof(layout->super), &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = encodeSuperBlockData(buffer, &layout->super);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = writeToBufferedWriter(writer,  getBufferContents(buffer),
Packit Service 310c69
                                 contentLength(buffer));
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  return flushBufferedWriter(writer);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int saveSingleFileConfiguration(IndexLayout *layout)
Packit Service 310c69
{
Packit Service 310c69
  int result = saveSubIndexRegions(layout);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  RegionTable  *table;
Packit Service 310c69
  unsigned int  numRegions;
Packit Service 310c69
  result = makeSingleFileRegionTable(layout, &numRegions, &table);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  BufferedWriter *writer = NULL;
Packit Service 310c69
  result = openLayoutWriter(layout, &layout->header, &writer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = writeSingleFileHeader(layout, table, numRegions, writer);
Packit Service 310c69
  FREE(table);
Packit Service 310c69
  freeBufferedWriter(writer);
Packit Service 310c69
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
void putIndexLayout(IndexLayout **layoutPtr)
Packit Service 310c69
{
Packit Service 310c69
  if (layoutPtr == NULL) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
  IndexLayout *layout = *layoutPtr;
Packit Service 310c69
  *layoutPtr = NULL;
Packit Service 310c69
  if ((layout == NULL) || (--layout->refCount > 0)) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  SubIndexLayout *sil = &layout->index;
Packit Service 310c69
  if (sil->saves != NULL) {
Packit Service 310c69
    unsigned int j;
Packit Service 310c69
    for (j = 0; j < layout->super.maxSaves; ++j) {
Packit Service 310c69
      IndexSaveLayout *isl = &sil->saves[j];
Packit Service 310c69
      FREE(isl->masterIndexZones);
Packit Service 310c69
      FREE(isl->openChapter);
Packit Service 310c69
      freeBuffer(&isl->indexStateBuffer);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  FREE(sil->saves);
Packit Service 310c69
Packit Service 310c69
  if (layout->factory != NULL) {
Packit Service 310c69
    putIOFactory(layout->factory);
Packit Service 310c69
  }
Packit Service 310c69
  FREE(layout);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
void getIndexLayout(IndexLayout *layout, IndexLayout **layoutPtr)
Packit Service 310c69
{
Packit Service 310c69
  ++layout->refCount;
Packit Service 310c69
  *layoutPtr = layout;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
const struct index_version *getIndexVersion(IndexLayout *layout)
Packit Service 310c69
{
Packit Service 310c69
  return &layout->indexVersion;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int writeIndexConfig(IndexLayout *layout, UdsConfiguration config)
Packit Service 310c69
{
Packit Service 310c69
  BufferedWriter *writer = NULL;
Packit Service 310c69
  int result = openLayoutWriter(layout, &layout->config, &writer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result, "failed to open config region");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = writeConfigContents(writer, config);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBufferedWriter(writer);
Packit Service 310c69
    return logErrorWithStringError(result, "failed to write config region");
Packit Service 310c69
  }
Packit Service 310c69
  result = flushBufferedWriter(writer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBufferedWriter(writer);
Packit Service 310c69
    return logErrorWithStringError(result, "cannot flush config writer");
Packit Service 310c69
  }
Packit Service 310c69
  freeBufferedWriter(writer);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int verifyIndexConfig(IndexLayout *layout, UdsConfiguration config)
Packit Service 310c69
{
Packit Service 310c69
  BufferedReader *reader = NULL;
Packit Service 310c69
  int result = openLayoutReader(layout, &layout->config, &reader);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result, "failed to open config reader");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  struct udsConfiguration storedConfig;
Packit Service 310c69
  result = readConfigContents(reader, &storedConfig);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBufferedReader(reader);
Packit Service 310c69
    return logErrorWithStringError(result, "failed to read config region");
Packit Service 310c69
  }
Packit Service 310c69
  freeBufferedReader(reader);
Packit Service 310c69
Packit Service 310c69
  return (areUdsConfigurationsEqual(&storedConfig, config)
Packit Service 310c69
          ? UDS_SUCCESS
Packit Service 310c69
          : UDS_NO_INDEX);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int openVolumeBufio(IndexLayout             *layout,
Packit Service 310c69
                    size_t                   blockSize,
Packit Service 310c69
                    unsigned int             reservedBuffers,
Packit Service 310c69
                    struct dm_bufio_client **clientPtr)
Packit Service 310c69
{
Packit Service 310c69
  off_t offset = layout->index.volume.startBlock * layout->super.blockSize;
Packit Service 310c69
  return makeBufio(layout->factory, offset, blockSize, reservedBuffers,
Packit Service 310c69
                   clientPtr);
Packit Service 310c69
}
Packit Service 310c69
#else
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int openVolumeRegion(IndexLayout *layout, IORegion **regionPtr)
Packit Service 310c69
{
Packit Service 310c69
  LayoutRegion *lr = &layout->index.volume;
Packit Service 310c69
  off_t start = lr->startBlock * layout->super.blockSize;
Packit Service 310c69
  size_t size = lr->numBlocks * layout->super.blockSize;
Packit Service 310c69
  int result =  makeIORegion(layout->factory, start, size, regionPtr);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logErrorWithStringError(result,
Packit Service 310c69
                                   "cannot access index volume region");
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
uint64_t getVolumeNonce(IndexLayout *layout)
Packit Service 310c69
{
Packit Service 310c69
  return layout->index.nonce;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static uint64_t generateIndexSaveNonce(uint64_t         volumeNonce,
Packit Service 310c69
                                       IndexSaveLayout *isl)
Packit Service 310c69
{
Packit Service 310c69
  struct SaveNonceData {
Packit Service 310c69
    IndexSaveData data;
Packit Service 310c69
    uint64_t      offset;
Packit Service 310c69
  } nonceData;
Packit Service 310c69
Packit Service 310c69
  nonceData.data = isl->saveData;
Packit Service 310c69
  nonceData.data.nonce = 0;
Packit Service 310c69
  nonceData.offset = isl->indexSave.startBlock;
Packit Service 310c69
Packit Service 310c69
  byte buffer[sizeof(nonceData)];
Packit Service 310c69
  size_t offset = 0;
Packit Service 310c69
  encodeUInt64LE(buffer, &offset, nonceData.data.timestamp);
Packit Service 310c69
  encodeUInt64LE(buffer, &offset, nonceData.data.nonce);
Packit Service 310c69
  encodeUInt32LE(buffer, &offset, nonceData.data.version);
Packit Service 310c69
  encodeUInt32LE(buffer, &offset, 0U);    // padding
Packit Service 310c69
  encodeUInt64LE(buffer, &offset, nonceData.offset);
Packit Service 310c69
  ASSERT_LOG_ONLY(offset == sizeof(nonceData),
Packit Service 310c69
                  "%zu bytes encoded of %zu expected",
Packit Service 310c69
                  offset, sizeof(nonceData));
Packit Service 310c69
  return generateSecondaryNonce(volumeNonce, buffer, sizeof(buffer));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static int validateIndexSaveLayout(IndexSaveLayout *isl,
Packit Service 310c69
                                   uint64_t         volumeNonce,
Packit Service 310c69
                                   uint64_t        *saveTimePtr)
Packit Service 310c69
{
Packit Service 310c69
  if (isl->saveType == NO_SAVE || isl->numZones == 0 ||
Packit Service 310c69
      isl->saveData.timestamp == 0)
Packit Service 310c69
  {
Packit Service 310c69
    return UDS_BAD_STATE;
Packit Service 310c69
  }
Packit Service 310c69
  if (isl->saveData.nonce != generateIndexSaveNonce(volumeNonce, isl)) {
Packit Service 310c69
    return UDS_BAD_STATE;
Packit Service 310c69
  }
Packit Service 310c69
  if (saveTimePtr != NULL) {
Packit Service 310c69
    *saveTimePtr = isl->saveData.timestamp;
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int selectOldestIndexSaveLayout(SubIndexLayout   *sil,
Packit Service 310c69
                                       unsigned int      maxSaves,
Packit Service 310c69
                                       IndexSaveLayout **islPtr)
Packit Service 310c69
{
Packit Service 310c69
  IndexSaveLayout *oldest = NULL;
Packit Service 310c69
  uint64_t         oldestTime = 0;
Packit Service 310c69
Packit Service 310c69
  // find the oldest valid or first invalid slot
Packit Service 310c69
  IndexSaveLayout *isl;
Packit Service 310c69
  for (isl = sil->saves; isl < sil->saves + maxSaves; ++isl) {
Packit Service 310c69
    uint64_t saveTime = 0;
Packit Service 310c69
    int result = validateIndexSaveLayout(isl, sil->nonce, &saveTime);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      saveTime = 0;
Packit Service 310c69
    }
Packit Service 310c69
    if (oldest == NULL || saveTime < oldestTime) {
Packit Service 310c69
      oldest = isl;
Packit Service 310c69
      oldestTime = saveTime;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  int result = ASSERT((oldest != NULL), "no oldest or free save slot");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  *islPtr = oldest;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int selectLatestIndexSaveLayout(SubIndexLayout   *sil,
Packit Service 310c69
                                       unsigned int      maxSaves,
Packit Service 310c69
                                       IndexSaveLayout **islPtr)
Packit Service 310c69
{
Packit Service 310c69
  IndexSaveLayout *latest = NULL;
Packit Service 310c69
  uint64_t         latestTime = 0;
Packit Service 310c69
Packit Service 310c69
  // find the latest valid save slot
Packit Service 310c69
  IndexSaveLayout *isl;
Packit Service 310c69
  for (isl = sil->saves; isl < sil->saves + maxSaves; ++isl) {
Packit Service 310c69
    uint64_t saveTime = 0;
Packit Service 310c69
    int result = validateIndexSaveLayout(isl, sil->nonce, &saveTime);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      continue;
Packit Service 310c69
    }
Packit Service 310c69
    if (saveTime > latestTime) {
Packit Service 310c69
      latest = isl;
Packit Service 310c69
      latestTime = saveTime;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (latest == NULL) {
Packit Service 310c69
    return UDS_INDEX_NOT_SAVED_CLEANLY;
Packit Service 310c69
  }
Packit Service 310c69
  *islPtr = latest;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static uint64_t getTimeMS(AbsTime time)
Packit Service 310c69
{
Packit Service 310c69
  time_t t = asTimeT(time);
Packit Service 310c69
  RelTime r = timeDifference(time, fromTimeT(t));
Packit Service 310c69
  return (uint64_t) t * 1000 + relTimeToMilliseconds(r);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int instantiateIndexSaveLayout(IndexSaveLayout *isl,
Packit Service 310c69
                                      SuperBlockData  *super,
Packit Service 310c69
                                      uint64_t         volumeNonce,
Packit Service 310c69
                                      unsigned int     numZones,
Packit Service 310c69
                                      IndexSaveType    saveType)
Packit Service 310c69
{
Packit Service 310c69
  int result = UDS_SUCCESS;
Packit Service 310c69
  if (isl->openChapter && saveType == IS_CHECKPOINT) {
Packit Service 310c69
    FREE(isl->openChapter);
Packit Service 310c69
    isl->openChapter = NULL;
Packit Service 310c69
  } else if (isl->openChapter == NULL && saveType == IS_SAVE) {
Packit Service 310c69
    result = ALLOCATE(1, LayoutRegion, "open chapter layout",
Packit Service 310c69
                      &isl->openChapter);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  if (numZones != isl->numZones) {
Packit Service 310c69
    if (isl->masterIndexZones != NULL) {
Packit Service 310c69
      FREE(isl->masterIndexZones);
Packit Service 310c69
    }
Packit Service 310c69
    result = ALLOCATE(numZones, LayoutRegion, "master index zone layouts",
Packit Service 310c69
                      &isl->masterIndexZones);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
    isl->numZones = numZones;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  populateIndexSaveLayout(isl, super, numZones, saveType);
Packit Service 310c69
Packit Service 310c69
  result = makeBuffer(INDEX_STATE_BUFFER_SIZE, &isl->indexStateBuffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  isl->read = isl->written = false;
Packit Service 310c69
  isl->saveType = saveType;
Packit Service 310c69
  memset(&isl->saveData, 0, sizeof(isl->saveData));
Packit Service 310c69
  isl->saveData.timestamp = getTimeMS(currentTime(CLOCK_REALTIME));
Packit Service 310c69
  isl->saveData.version   = 1;
Packit Service 310c69
Packit Service 310c69
  isl->saveData.nonce = generateIndexSaveNonce(volumeNonce, isl);
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int invalidateOldSave(IndexLayout *layout, IndexSaveLayout *isl)
Packit Service 310c69
{
Packit Service 310c69
  uint64_t startBlock = isl->indexSave.startBlock;
Packit Service 310c69
  uint64_t saveBlocks = isl->indexSave.numBlocks;
Packit Service 310c69
  unsigned int save   = isl->indexSave.instance;
Packit Service 310c69
Packit Service 310c69
  int result = resetIndexSaveLayout(isl, &startBlock, saveBlocks,
Packit Service 310c69
                                    layout->super.pageMapBlocks, save);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return writeIndexSaveLayout(layout, isl);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int setupIndexSaveSlot(IndexLayout   *layout,
Packit Service 310c69
                       unsigned int   numZones,
Packit Service 310c69
                       IndexSaveType  saveType,
Packit Service 310c69
                       unsigned int  *saveSlotPtr)
Packit Service 310c69
{
Packit Service 310c69
  SubIndexLayout *sil = &layout->index;
Packit Service 310c69
Packit Service 310c69
  IndexSaveLayout *isl = NULL;
Packit Service 310c69
  int result = selectOldestIndexSaveLayout(sil, layout->super.maxSaves, &isl;;
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = invalidateOldSave(layout, isl);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = instantiateIndexSaveLayout(isl, &layout->super, sil->nonce,
Packit Service 310c69
                                      numZones, saveType);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  *saveSlotPtr = isl - sil->saves;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int findLatestIndexSaveSlot(IndexLayout  *layout,
Packit Service 310c69
                            unsigned int *numZonesPtr,
Packit Service 310c69
                            unsigned int *slotPtr)
Packit Service 310c69
{
Packit Service 310c69
  SubIndexLayout *sil = &layout->index;
Packit Service 310c69
Packit Service 310c69
  IndexSaveLayout *isl = NULL;
Packit Service 310c69
  int result = selectLatestIndexSaveLayout(sil, layout->super.maxSaves, &isl;;
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (numZonesPtr != NULL) {
Packit Service 310c69
    *numZonesPtr = isl->numZones;
Packit Service 310c69
  }
Packit Service 310c69
  if (slotPtr != NULL) {
Packit Service 310c69
    *slotPtr = isl - sil->saves;
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int makeIndexSaveRegionTable(IndexSaveLayout  *isl,
Packit Service 310c69
                                    unsigned int     *numRegionsPtr,
Packit Service 310c69
                                    RegionTable     **tablePtr)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int numRegions =
Packit Service 310c69
    1 +                         // header
Packit Service 310c69
    1 +                         // index page map
Packit Service 310c69
    isl->numZones +             // master index zones
Packit Service 310c69
    (bool) isl->openChapter;    // open chapter if needed
Packit Service 310c69
Packit Service 310c69
  if (isl->freeSpace.numBlocks > 0) {
Packit Service 310c69
    numRegions++;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  RegionTable *table;
Packit Service 310c69
  int result = ALLOCATE_EXTENDED(RegionTable, numRegions, LayoutRegion,
Packit Service 310c69
                                 "layout region table for ISL", &table);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  LayoutRegion *lr = &table->regions[0];
Packit Service 310c69
  *lr++ = isl->header;
Packit Service 310c69
  *lr++ = isl->indexPageMap;
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < isl->numZones; ++z) {
Packit Service 310c69
    *lr++ = isl->masterIndexZones[z];
Packit Service 310c69
  }
Packit Service 310c69
  if (isl->openChapter) {
Packit Service 310c69
    *lr++ = *isl->openChapter;
Packit Service 310c69
  }
Packit Service 310c69
  if (isl->freeSpace.numBlocks > 0) {
Packit Service 310c69
    *lr++ = isl->freeSpace;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = ASSERT((lr == &table->regions[numRegions]),
Packit Service 310c69
                  "incorrect number of ISL regions");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  *numRegionsPtr = numRegions;
Packit Service 310c69
  *tablePtr = table;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static unsigned int regionTypeForSaveType(IndexSaveType saveType)
Packit Service 310c69
{
Packit Service 310c69
  switch (saveType) {
Packit Service 310c69
    case IS_SAVE:
Packit Service 310c69
      return RH_TYPE_SAVE;
Packit Service 310c69
Packit Service 310c69
    case IS_CHECKPOINT:
Packit Service 310c69
      return RH_TYPE_CHECKPOINT;
Packit Service 310c69
Packit Service 310c69
    default:
Packit Service 310c69
      break;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return RH_TYPE_UNSAVED;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int writeIndexSaveHeader(IndexSaveLayout *isl,
Packit Service 310c69
                                RegionTable     *table,
Packit Service 310c69
                                unsigned int     numRegions,
Packit Service 310c69
                                BufferedWriter  *writer)
Packit Service 310c69
{
Packit Service 310c69
  size_t payload = sizeof(isl->saveData);
Packit Service 310c69
  if (isl->indexStateBuffer != NULL) {
Packit Service 310c69
    payload += contentLength(isl->indexStateBuffer);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  table->header = (RegionHeader) {
Packit Service 310c69
    .magic        = REGION_MAGIC,
Packit Service 310c69
    .regionBlocks = isl->indexSave.numBlocks,
Packit Service 310c69
    .type         = regionTypeForSaveType(isl->saveType),
Packit Service 310c69
    .version      = 1,
Packit Service 310c69
    .numRegions   = numRegions,
Packit Service 310c69
    .payload      = payload,
Packit Service 310c69
  };
Packit Service 310c69
Packit Service 310c69
  size_t tableSize = sizeof(RegionTable) + numRegions * sizeof(LayoutRegion);
Packit Service 310c69
  Buffer *buffer;
Packit Service 310c69
  int result = makeBuffer(tableSize, &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = encodeRegionHeader(buffer, &table->header);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < numRegions; i++) {
Packit Service 310c69
    result = encodeLayoutRegion(buffer, &table->regions[i]);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      freeBuffer(&buffer);
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_LOG_ONLY(contentLength(buffer) == tableSize,
Packit Service 310c69
                           "%zu bytes encoded of %zu expected",
Packit Service 310c69
                           contentLength(buffer), tableSize);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = writeToBufferedWriter(writer,  getBufferContents(buffer),
Packit Service 310c69
                                 contentLength(buffer));
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = makeBuffer(sizeof(isl->saveData), &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = encodeIndexSaveData(buffer,  &isl->saveData);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = writeToBufferedWriter(writer, getBufferContents(buffer),
Packit Service 310c69
                                 contentLength(buffer));
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (isl->indexStateBuffer != NULL) {
Packit Service 310c69
    result = writeToBufferedWriter(writer,
Packit Service 310c69
                                   getBufferContents(isl->indexStateBuffer),
Packit Service 310c69
                                   contentLength(isl->indexStateBuffer));
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return flushBufferedWriter(writer);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static int writeIndexSaveLayout(IndexLayout *layout, IndexSaveLayout *isl)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int  numRegions;
Packit Service 310c69
  RegionTable  *table;
Packit Service 310c69
  int result = makeIndexSaveRegionTable(isl, &numRegions, &table);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  BufferedWriter *writer = NULL;
Packit Service 310c69
  result = openLayoutWriter(layout, &isl->header, &writer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(table);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = writeIndexSaveHeader(isl, table, numRegions, writer);
Packit Service 310c69
  FREE(table);
Packit Service 310c69
  freeBufferedWriter(writer);
Packit Service 310c69
Packit Service 310c69
  isl->written = true;
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int commitIndexSave(IndexLayout *layout, unsigned int saveSlot)
Packit Service 310c69
{
Packit Service 310c69
  int result = ASSERT((saveSlot < layout->super.maxSaves),
Packit Service 310c69
                      "save slot out of range");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  IndexSaveLayout *isl = &layout->index.saves[saveSlot];
Packit Service 310c69
Packit Service 310c69
  if (bufferUsed(isl->indexStateBuffer) == 0) {
Packit Service 310c69
    return logErrorWithStringError(UDS_UNEXPECTED_RESULT,
Packit Service 310c69
                                   "%s: no index state data saved", __func__);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return writeIndexSaveLayout(layout, isl);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
Packit Service 310c69
static void mutilateIndexSaveInfo(IndexSaveLayout *isl)
Packit Service 310c69
{
Packit Service 310c69
  memset(&isl->saveData, 0, sizeof(isl->saveData));
Packit Service 310c69
  isl->read = isl->written = 0;
Packit Service 310c69
  isl->saveType = NO_SAVE;
Packit Service 310c69
  isl->numZones = 0;
Packit Service 310c69
  freeBuffer(&isl->indexStateBuffer);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int cancelIndexSave(IndexLayout *layout, unsigned int saveSlot)
Packit Service 310c69
{
Packit Service 310c69
  int result = ASSERT((saveSlot < layout->super.maxSaves),
Packit Service 310c69
                      "save slot out of range");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  mutilateIndexSaveInfo(&layout->index.saves[saveSlot]);
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int discardIndexSaves(IndexLayout *layout, bool all)
Packit Service 310c69
{
Packit Service 310c69
  int result = UDS_SUCCESS;
Packit Service 310c69
  SubIndexLayout *sil = &layout->index;
Packit Service 310c69
Packit Service 310c69
  if (all) {
Packit Service 310c69
    unsigned int i;
Packit Service 310c69
    for (i = 0; i < layout->super.maxSaves; ++i) {
Packit Service 310c69
      IndexSaveLayout *isl = &sil->saves[i];
Packit Service 310c69
      result = firstError(result, invalidateOldSave(layout, isl));
Packit Service 310c69
    }
Packit Service 310c69
  } else {
Packit Service 310c69
    IndexSaveLayout *isl;
Packit Service 310c69
    result = selectLatestIndexSaveLayout(sil, layout->super.maxSaves, &isl;;
Packit Service 310c69
    if (result == UDS_SUCCESS) {
Packit Service 310c69
      result = invalidateOldSave(layout, isl);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static int createIndexLayout(IndexLayout            *layout,
Packit Service 310c69
                             uint64_t                size,
Packit Service 310c69
                             const UdsConfiguration  config)
Packit Service 310c69
{
Packit Service 310c69
  if (config == NULL) {
Packit Service 310c69
    return UDS_CONF_PTR_REQUIRED;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  SaveLayoutSizes sizes;
Packit Service 310c69
  int result = computeSizes(&sizes, config, UDS_BLOCK_SIZE, 0);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (size < sizes.totalBlocks * sizes.blockSize) {
Packit Service 310c69
    return logErrorWithStringError(UDS_INSUFFICIENT_INDEX_SPACE,
Packit Service 310c69
                                   "layout requires at least %" PRIu64 
Packit Service 310c69
                                   " bytes",
Packit Service 310c69
                                   sizes.totalBlocks * sizes.blockSize);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = initSingleFileLayout(layout, layout->offset, size, &sizes);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = saveSingleFileConfiguration(layout);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
Buffer *getIndexStateBuffer(IndexLayout *layout, unsigned int slot)
Packit Service 310c69
{
Packit Service 310c69
  return layout->index.saves[slot].indexStateBuffer;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
static int findLayoutRegion(IndexLayout   *layout,
Packit Service 310c69
                            unsigned int   slot,
Packit Service 310c69
                            const char    *operation,
Packit Service 310c69
                            RegionKind     kind,
Packit Service 310c69
                            unsigned int   zone,
Packit Service 310c69
                            LayoutRegion **lrPtr)
Packit Service 310c69
{
Packit Service 310c69
  int result = ASSERT((slot < layout->super.maxSaves), "%s not started",
Packit Service 310c69
                  operation);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  IndexSaveLayout *isl = &layout->index.saves[slot];
Packit Service 310c69
Packit Service 310c69
  LayoutRegion *lr = NULL;
Packit Service 310c69
  switch (kind) {
Packit Service 310c69
    case RL_KIND_INDEX_PAGE_MAP:
Packit Service 310c69
      lr = &isl->indexPageMap;
Packit Service 310c69
      break;
Packit Service 310c69
Packit Service 310c69
    case RL_KIND_OPEN_CHAPTER:
Packit Service 310c69
      if (isl->openChapter == NULL) {
Packit Service 310c69
        return logErrorWithStringError(UDS_UNEXPECTED_RESULT,
Packit Service 310c69
                                       "%s: %s has no open chapter",
Packit Service 310c69
                                       __func__, operation);
Packit Service 310c69
      }
Packit Service 310c69
      lr = isl->openChapter;
Packit Service 310c69
      break;
Packit Service 310c69
Packit Service 310c69
    case RL_KIND_MASTER_INDEX:
Packit Service 310c69
      if (isl->masterIndexZones == NULL || zone >= isl->numZones) {
Packit Service 310c69
        return logErrorWithStringError(UDS_UNEXPECTED_RESULT,
Packit Service 310c69
                                       "%s: %s has no master index zone %u",
Packit Service 310c69
                                       __func__, operation, zone);
Packit Service 310c69
      }
Packit Service 310c69
      lr = &isl->masterIndexZones[zone];
Packit Service 310c69
      break;
Packit Service 310c69
Packit Service 310c69
    default:
Packit Service 310c69
      return logErrorWithStringError(UDS_INVALID_ARGUMENT,
Packit Service 310c69
                                     "%s: unexpected kind %u",
Packit Service 310c69
                                     __func__, kind);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  *lrPtr = lr;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int openIndexBufferedReader(IndexLayout     *layout,
Packit Service 310c69
                            unsigned int     slot,
Packit Service 310c69
                            RegionKind       kind,
Packit Service 310c69
                            unsigned int     zone,
Packit Service 310c69
                            BufferedReader **readerPtr)
Packit Service 310c69
{
Packit Service 310c69
  LayoutRegion *lr = NULL;
Packit Service 310c69
  int result = findLayoutRegion(layout, slot, "load", kind, zone, &lr);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  return openLayoutReader(layout, lr, readerPtr);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int openIndexBufferedWriter(IndexLayout     *layout,
Packit Service 310c69
                            unsigned int     slot,
Packit Service 310c69
                            RegionKind       kind,
Packit Service 310c69
                            unsigned int     zone,
Packit Service 310c69
                            BufferedWriter **writerPtr)
Packit Service 310c69
{
Packit Service 310c69
  LayoutRegion *lr = NULL;
Packit Service 310c69
  int result = findLayoutRegion(layout, slot, "save", kind, zone, &lr);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  return openLayoutWriter(layout, lr, writerPtr);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/*****************************************************************************/
Packit Service 310c69
int makeIndexLayoutFromFactory(IOFactory               *factory,
Packit Service 310c69
                               off_t                    offset,
Packit Service 310c69
                               uint64_t                 namedSize,
Packit Service 310c69
                               bool                     newLayout,
Packit Service 310c69
                               const UdsConfiguration   config,
Packit Service 310c69
                               IndexLayout            **layoutPtr)
Packit Service 310c69
{
Packit Service 310c69
  // Get the device size and round it down to a multiple of UDS_BLOCK_SIZE.
Packit Service 310c69
  size_t size = getWritableSize(factory) & -UDS_BLOCK_SIZE;
Packit Service 310c69
  if (namedSize > size) {
Packit Service 310c69
    return logErrorWithStringError(UDS_INSUFFICIENT_INDEX_SPACE,
Packit Service 310c69
                                   "index storage (%zu) is smaller than the"
Packit Service 310c69
                                   " requested size %llu",
Packit Service 310c69
                                   size, namedSize);
Packit Service 310c69
  }
Packit Service 310c69
  if ((namedSize > 0) && (namedSize < size)) {
Packit Service 310c69
    size = namedSize;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Get the index size according the the config
Packit Service 310c69
  uint64_t configSize;
Packit Service 310c69
  int result = udsComputeIndexSize(config, 0, &configSize);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  if (size < configSize) {
Packit Service 310c69
    return logErrorWithStringError(UDS_INSUFFICIENT_INDEX_SPACE,
Packit Service 310c69
                                   "index storage (%zu) is smaller than the"
Packit Service 310c69
                                   " required size %llu",
Packit Service 310c69
                                   size, configSize);
Packit Service 310c69
  }
Packit Service 310c69
  size = configSize;
Packit Service 310c69
Packit Service 310c69
  IndexLayout *layout = NULL;
Packit Service 310c69
  result = ALLOCATE(1, IndexLayout, __func__, &layout);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  layout->refCount = 1;
Packit Service 310c69
Packit Service 310c69
  getIOFactory(factory);
Packit Service 310c69
  layout->factory = factory;
Packit Service 310c69
  layout->offset  = offset;
Packit Service 310c69
Packit Service 310c69
  if (newLayout) {
Packit Service 310c69
    // Populate the layout from the UDSConfiguration
Packit Service 310c69
    result = createIndexLayout(layout, size, config);
Packit Service 310c69
  } else {
Packit Service 310c69
    // Populate the layout from the saved index.
Packit Service 310c69
    result = loadIndexLayout(layout);
Packit Service 310c69
  }
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    putIndexLayout(&layout);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  *layoutPtr = layout;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}