|
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
|