/* * Copyright (c) 2020 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/vioRead.c#1 $ */ #include "vioRead.h" #include "logger.h" #include "blockMap.h" #include "dataVIO.h" #include "vdoInternal.h" #include "vioWrite.h" /** * Do the modify-write part of a read-modify-write cycle. This callback is * registered in readBlock(). * * @param completion The DataVIO which has just finished its read **/ static void modifyForPartialWrite(VDOCompletion *completion) { DataVIO *dataVIO = asDataVIO(completion); assertInLogicalZone(dataVIO); if (completion->result != VDO_SUCCESS) { completeDataVIO(completion); return; } completion->layer->applyPartialWrite(dataVIO); VIO *vio = dataVIOAsVIO(dataVIO); vio->operation = VIO_WRITE | (vio->operation & ~VIO_READ_WRITE_MASK); dataVIO->isPartialWrite = true; launchWriteDataVIO(dataVIO); } /** * Read a block asynchronously. This is the callback registered in * readBlockMapping(). * * @param completion The DataVIO to read **/ static void readBlock(VDOCompletion *completion) { if (completion->result != VDO_SUCCESS) { completeDataVIO(completion); return; } DataVIO *dataVIO = asDataVIO(completion); VIO *vio = asVIO(completion); completion->callback = (isReadVIO(vio) ? completeDataVIO : modifyForPartialWrite); if (dataVIO->mapped.pbn == ZERO_BLOCK) { completion->layer->zeroDataVIO(dataVIO); invokeCallback(completion); return; } vio->physical = dataVIO->mapped.pbn; dataVIO->lastAsyncOperation = READ_DATA; completion->layer->readData(dataVIO); } /** * Read the DataVIO's mapping from the block map. This callback is registered * in launchReadDataVIO(). * * @param completion The DataVIO to be read **/ static void readBlockMapping(VDOCompletion *completion) { if (completion->result != VDO_SUCCESS) { completeDataVIO(completion); return; } DataVIO *dataVIO = asDataVIO(completion); assertInLogicalZone(dataVIO); setLogicalCallback(dataVIO, readBlock, THIS_LOCATION("$F;cb=readBlock")); dataVIO->lastAsyncOperation = GET_MAPPED_BLOCK; getMappedBlockAsync(dataVIO); } /**********************************************************************/ void launchReadDataVIO(DataVIO *dataVIO) { assertInLogicalZone(dataVIO); dataVIO->lastAsyncOperation = FIND_BLOCK_MAP_SLOT; // Go find the block map slot for the LBN mapping. findBlockMapSlotAsync(dataVIO, readBlockMapping, getLogicalZoneThreadID(dataVIO->logical.zone)); } /** * Release the logical block lock which a read DataVIO obtained now that it * is done. * * @param completion The DataVIO **/ static void releaseLogicalLock(VDOCompletion *completion) { DataVIO *dataVIO = asDataVIO(completion); assertInLogicalZone(dataVIO); releaseLogicalBlockLock(dataVIO); vioDoneCallback(completion); } /** * Clean up a DataVIO which has finished processing a read. * * @param dataVIO The DataVIO to clean up **/ void cleanupReadDataVIO(DataVIO *dataVIO) { launchLogicalCallback(dataVIO, releaseLogicalLock, THIS_LOCATION("$F;cb=releaseLL")); }