Blame source/vdo/base/allocatingVIO.h

Packit b55c50
/*
Packit b55c50
 * Copyright (c) 2020 Red Hat, Inc.
Packit b55c50
 *
Packit b55c50
 * This program is free software; you can redistribute it and/or
Packit b55c50
 * modify it under the terms of the GNU General Public License
Packit b55c50
 * as published by the Free Software Foundation; either version 2
Packit b55c50
 * of the License, or (at your option) any later version.
Packit b55c50
 * 
Packit b55c50
 * This program is distributed in the hope that it will be useful,
Packit b55c50
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b55c50
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit b55c50
 * GNU General Public License for more details.
Packit b55c50
 * 
Packit b55c50
 * You should have received a copy of the GNU General Public License
Packit b55c50
 * along with this program; if not, write to the Free Software
Packit b55c50
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit b55c50
 * 02110-1301, USA. 
Packit b55c50
 *
Packit b55c50
 * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/allocatingVIO.h#4 $
Packit b55c50
 */
Packit b55c50
Packit b55c50
#ifndef ALLOCATING_VIO_H
Packit b55c50
#define ALLOCATING_VIO_H
Packit b55c50
Packit b55c50
#include "atomic.h"
Packit b55c50
#include "pbnLock.h"
Packit b55c50
#include "physicalZone.h"
Packit b55c50
#include "types.h"
Packit b55c50
#include "vio.h"
Packit b55c50
#include "waitQueue.h"
Packit b55c50
Packit b55c50
typedef void AllocationCallback(AllocatingVIO *allocationVIO);
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * A VIO which can receive an allocation from the block allocator. Currently,
Packit b55c50
 * these are used both for servicing external data requests and for compressed
Packit b55c50
 * block writes.
Packit b55c50
 **/
Packit b55c50
struct allocatingVIO {
Packit b55c50
  /** The underlying VIO */
Packit b55c50
  VIO                 vio;
Packit b55c50
Packit b55c50
  /** The WaitQueue entry structure */
Packit b55c50
  Waiter              waiter;
Packit b55c50
Packit b55c50
  /** The physical zone in which to allocate a physical block */
Packit b55c50
  PhysicalZone       *zone;
Packit b55c50
Packit b55c50
  /** The block allocated to this VIO */
Packit b55c50
  PhysicalBlockNumber allocation;
Packit b55c50
Packit b55c50
  /**
Packit b55c50
   * If non-NULL, the pooled PBN lock held on the allocated block. Must be a
Packit b55c50
   * write lock until the block has been written, after which it will become a
Packit b55c50
   * read lock.
Packit b55c50
   **/
Packit b55c50
  PBNLock            *allocationLock;
Packit b55c50
Packit b55c50
  /** The type of write lock to obtain on the allocated block */
Packit b55c50
  PBNLockType         writeLockType;
Packit b55c50
Packit b55c50
  /** The number of zones in which this VIO has attempted an allocation */
Packit b55c50
  ZoneCount           allocationAttempts;
Packit b55c50
Packit b55c50
  /** Whether this VIO should wait for a clean slab */
Packit b55c50
  bool                waitForCleanSlab;
Packit b55c50
Packit b55c50
  /** The function to call once allocation is complete */
Packit b55c50
  AllocationCallback *allocationCallback;
Packit b55c50
};
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Convert a VIO to an AllocatingVIO.
Packit b55c50
 *
Packit b55c50
 * @param vio  The VIO to convert
Packit b55c50
 *
Packit b55c50
 * @return The VIO as an AllocatingVIO
Packit b55c50
 **/
Packit b55c50
static inline AllocatingVIO *vioAsAllocatingVIO(VIO *vio)
Packit b55c50
{
Packit b55c50
  STATIC_ASSERT(offsetof(AllocatingVIO, vio) == 0);
Packit b55c50
  ASSERT_LOG_ONLY(((vio->type == VIO_TYPE_DATA)
Packit b55c50
                   || (vio->type == VIO_TYPE_COMPRESSED_BLOCK)),
Packit b55c50
                  "VIO is an AllocatingVIO");
Packit b55c50
  return (AllocatingVIO *) vio;
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Convert an AllocatingVIO to a VIO.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO to convert
Packit b55c50
 *
Packit b55c50
 * @return The AllocatingVIO as a VIO
Packit b55c50
 **/
Packit b55c50
static inline VIO *allocatingVIOAsVIO(AllocatingVIO *allocatingVIO)
Packit b55c50
{
Packit b55c50
  return &allocatingVIO->vio;
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Convert a generic VDOCompletion to an AllocatingVIO.
Packit b55c50
 *
Packit b55c50
 * @param completion  The completion to convert
Packit b55c50
 *
Packit b55c50
 * @return The completion as an AllocatingVIO
Packit b55c50
 **/
Packit b55c50
static inline AllocatingVIO *asAllocatingVIO(VDOCompletion *completion)
Packit b55c50
{
Packit b55c50
  return vioAsAllocatingVIO(asVIO(completion));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Convert an AllocatingVIO to a generic completion.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO to convert
Packit b55c50
 *
Packit b55c50
 * @return The AllocatingVIO as a completion
Packit b55c50
 **/
Packit b55c50
static inline
Packit b55c50
VDOCompletion *allocatingVIOAsCompletion(AllocatingVIO *allocatingVIO)
Packit b55c50
{
Packit b55c50
  return vioAsCompletion(allocatingVIOAsVIO(allocatingVIO));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Convert an AllocatingVIO to a generic wait queue entry.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO to convert
Packit b55c50
 *
Packit b55c50
 * @return The AllocatingVIO as a wait queue entry
Packit b55c50
 **/
Packit b55c50
static inline Waiter *allocatingVIOAsWaiter(AllocatingVIO *allocatingVIO)
Packit b55c50
{
Packit b55c50
  return &allocatingVIO->waiter;
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Convert an AllocatingVIO's generic wait queue entry back to the
Packit b55c50
 * AllocatingVIO.
Packit b55c50
 *
Packit b55c50
 * @param waiter  The wait queue entry to convert
Packit b55c50
 *
Packit b55c50
 * @return The wait queue entry as an AllocatingVIO
Packit b55c50
 **/
Packit b55c50
static inline AllocatingVIO *waiterAsAllocatingVIO(Waiter *waiter)
Packit b55c50
{
Packit b55c50
  if (waiter == NULL) {
Packit b55c50
    return NULL;
Packit b55c50
  }
Packit b55c50
Packit b55c50
  return
Packit b55c50
    (AllocatingVIO *) ((uintptr_t) waiter - offsetof(AllocatingVIO, waiter));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Check whether an AllocatingVIO is a compressed block write.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO to check
Packit b55c50
 *
Packit b55c50
 * @return true if the AllocatingVIO is a compressed block write
Packit b55c50
 **/
Packit b55c50
static inline bool isCompressedWriteAllocatingVIO(AllocatingVIO *allocatingVIO)
Packit b55c50
{
Packit b55c50
  return isCompressedWriteVIO(allocatingVIOAsVIO(allocatingVIO));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Add a trace record for the current source location.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO structure to be updated
Packit b55c50
 * @param location       The source-location descriptor to be recorded
Packit b55c50
 **/
Packit b55c50
static inline void allocatingVIOAddTraceRecord(AllocatingVIO *allocatingVIO,
Packit b55c50
                                               TraceLocation  location)
Packit b55c50
{
Packit b55c50
  vioAddTraceRecord(allocatingVIOAsVIO(allocatingVIO), location);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Get the VDO from an AllocatingVIO.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO from which to get the VDO
Packit b55c50
 *
Packit b55c50
 * @return The VDO to which an AllocatingVIO belongs
Packit b55c50
 **/
Packit b55c50
static inline VDO *getVDOFromAllocatingVIO(AllocatingVIO *allocatingVIO)
Packit b55c50
{
Packit b55c50
  return allocatingVIOAsVIO(allocatingVIO)->vdo;
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Check that an AllocatingVIO is running on the physical zone thread in
Packit b55c50
 * which it did its allocation.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO in question
Packit b55c50
 **/
Packit b55c50
static inline void assertInPhysicalZone(AllocatingVIO *allocatingVIO)
Packit b55c50
{
Packit b55c50
  ThreadID expected = getPhysicalZoneThreadID(allocatingVIO->zone);
Packit b55c50
  ThreadID threadID = getCallbackThreadID();
Packit b55c50
  ASSERT_LOG_ONLY((expected == threadID),
Packit b55c50
                  "AllocatingVIO for allocated physical block %" PRIu64
Packit b55c50
                  " on thread %u, should be on thread %u",
Packit b55c50
                  allocatingVIO->allocation, threadID, expected);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Set a callback as a physical block operation in an AllocatingVIO's allocated
Packit b55c50
 * zone.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO
Packit b55c50
 * @param callback       The callback to set
Packit b55c50
 * @param location       The tracing info for the call site
Packit b55c50
 **/
Packit b55c50
static inline void setPhysicalZoneCallback(AllocatingVIO *allocatingVIO,
Packit b55c50
                                           VDOAction     *callback,
Packit b55c50
                                           TraceLocation  location)
Packit b55c50
{
Packit b55c50
  setCallback(allocatingVIOAsCompletion(allocatingVIO), callback,
Packit b55c50
              getPhysicalZoneThreadID(allocatingVIO->zone));
Packit b55c50
  allocatingVIOAddTraceRecord(allocatingVIO, location);
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Set a callback as a physical block operation in an AllocatingVIO's allocated
Packit b55c50
 * zone and invoke it immediately.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO
Packit b55c50
 * @param callback       The callback to invoke
Packit b55c50
 * @param location       The tracing info for the call site
Packit b55c50
 **/
Packit b55c50
static inline void launchPhysicalZoneCallback(AllocatingVIO *allocatingVIO,
Packit b55c50
                                              VDOAction     *callback,
Packit b55c50
                                              TraceLocation  location)
Packit b55c50
{
Packit b55c50
  setPhysicalZoneCallback(allocatingVIO, callback, location);
Packit b55c50
  invokeCallback(allocatingVIOAsCompletion(allocatingVIO));
Packit b55c50
}
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Allocate a data block to an AllocatingVIO.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO which needs an allocation
Packit b55c50
 * @param selector       The allocation selector for deciding which physical
Packit b55c50
 *                       zone to allocate from
Packit b55c50
 * @param writeLockType  The type of write lock to obtain on the block
Packit b55c50
 * @param callback       The function to call once the allocation is complete
Packit b55c50
 **/
Packit b55c50
void allocateDataBlock(AllocatingVIO      *allocatingVIO,
Packit b55c50
                       AllocationSelector *selector,
Packit b55c50
                       PBNLockType         writeLockType,
Packit b55c50
                       AllocationCallback *callback);
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Release the PBN lock on the allocated block. If the reference to the locked
Packit b55c50
 * block is still provisional, it will be released as well.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The lock holder
Packit b55c50
 **/
Packit b55c50
void releaseAllocationLock(AllocatingVIO *allocatingVIO);
Packit b55c50
Packit b55c50
/**
Packit b55c50
 * Reset an AllocatingVIO after it has done an allocation.
Packit b55c50
 *
Packit b55c50
 * @param allocatingVIO  The AllocatingVIO
Packit b55c50
 **/
Packit b55c50
void resetAllocation(AllocatingVIO *allocatingVIO);
Packit b55c50
Packit b55c50
#endif // ALLOCATING_VIO_H