/* * 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/kernel/dataKVIO.h#5 $ */ #ifndef DATA_KVIO_H #define DATA_KVIO_H #include "dataVIO.h" #include "kvio.h" #include "uds-block.h" typedef struct { /* * The BIO which was received from the device mapper to initiate an I/O * request. This field will be non-NULL only until the request is * acknowledged. */ BIO *bio; // Cached copies of fields from the bio which will need to be reset after // we're done. void *private; void *endIO; // This is a copy of the bi_rw field of the BIO which sadly is not just // a boolean read-write flag, but also includes other flag bits. unsigned long rw; } ExternalIORequest; /* Dedupe support */ struct dedupeContext { UdsRequest udsRequest; struct list_head pendingList; Jiffies submissionTime; Atomic32 requestState; int status; bool isPending; /** Hash of the associated VIO (NULL if not calculated) */ const UdsChunkName *chunkName; }; typedef struct { /** * A pointer to a block that holds the data from the last read operation. **/ char *data; /** * Temporary storage for doing reads from the underlying device. **/ char *buffer; /** * A bio structure wrapping the buffer. **/ BIO *bio; /** * Callback to invoke after completing the read I/O operation. **/ DataKVIOCallback callback; /** * Mapping state passed to kvdoReadBlock(), used to determine whether * the data must be uncompressed. **/ BlockMappingState mappingState; /** * The result code of the read attempt. **/ int status; } ReadBlock; struct dataKVIO { /* The embedded base code's DataVIO */ DataVIO dataVIO; /* The embedded KVIO */ KVIO kvio; /* The BIO from the request which is being serviced by this KVIO. */ ExternalIORequest externalIORequest; /* Dedupe */ DedupeContext dedupeContext; /* Read cache */ ReadBlock readBlock; /* partial block support */ BlockSize offset; bool isPartial; /* discard support */ bool hasDiscardPermit; DiscardSize remainingDiscard; /** * A copy of user data written, so we can do additional processing * (dedupe, compression) after acknowledging the I/O operation and * thus losing access to the original data. * * Also used as buffer space for read-modify-write cycles when * emulating smaller-than-blockSize I/O operations. **/ char *dataBlock; /** A bio structure describing the #dataBlock buffer. */ BIO *dataBlockBio; /** A block used as output during compression or uncompression. */ char *scratchBlock; }; /** * Convert a KVIO to a DataKVIO. * * @param kvio The KVIO to convert * * @return The KVIO as a DataKVIO **/ static inline DataKVIO *kvioAsDataKVIO(KVIO *kvio) { ASSERT_LOG_ONLY(isData(kvio), "KVIO is a DataKVIO"); return container_of(kvio, DataKVIO, kvio); } /** * Convert a DataKVIO to a KVIO. * * @param dataKVIO The DataKVIO to convert * * @return The DataKVIO as a KVIO **/ static inline KVIO *dataKVIOAsKVIO(DataKVIO *dataKVIO) { return &dataKVIO->kvio; } /** * Returns a pointer to the DataKVIO wrapping a DataVIO. * * @param dataVIO the DataVIO * * @return the DataKVIO **/ static inline DataKVIO *dataVIOAsDataKVIO(DataVIO *dataVIO) { return container_of(dataVIO, DataKVIO, dataVIO); } /** * Returns a pointer to the KVIO associated with a DataVIO. * * @param dataVIO the DataVIO * * @return the KVIO **/ static inline KVIO *dataVIOAsKVIO(DataVIO *dataVIO) { return dataKVIOAsKVIO(dataVIOAsDataKVIO(dataVIO)); } /** * Returns a pointer to the DataKVIO wrapping a work item. * * @param item the work item * * @return the DataKVIO **/ static inline DataKVIO *workItemAsDataKVIO(KvdoWorkItem *item) { return kvioAsDataKVIO(workItemAsKVIO(item)); } /** * Get the WorkItem from a DataKVIO. * * @param dataKVIO The DataKVIO * * @return the DataKVIO's work item **/ static inline KvdoWorkItem *workItemFromDataKVIO(DataKVIO *dataKVIO) { return &dataKVIOAsKVIO(dataKVIO)->enqueueable.workItem; } /** * Get the BIO from a DataKVIO. * * @param dataKVIO The DataKVIO from which to get the BIO * * @return The DataKVIO's BIO **/ static inline BIO *getBIOFromDataKVIO(DataKVIO *dataKVIO) { return dataKVIOAsKVIO(dataKVIO)->bio; } /** * Get the KernelLayer from a DataKVIO. * * @param dataKVIO The DataKVIO from which to get the KernelLayer * * @return The DataKVIO's KernelLayer **/ static inline KernelLayer *getLayerFromDataKVIO(DataKVIO *dataKVIO) { return dataKVIOAsKVIO(dataKVIO)->layer; } /** * Set up and enqueue a DataKVIO's work item to be processed in the base code * context. * * @param dataKVIO The DataKVIO with the work item to be run * @param work The function pointer to execute * @param statsFunction A function pointer to record for stats, or NULL * @param action Action code, mapping to a relative priority **/ static inline void enqueueDataKVIO(DataKVIO *dataKVIO, KvdoWorkFunction work, void *statsFunction, unsigned int action) { enqueueKVIO(dataKVIOAsKVIO(dataKVIO), work, statsFunction, action); } /** * Enqueue a DataKVIO on a work queue. * * @param queue The queue * @param dataKVIO The DataKVIO **/ static inline void enqueueDataKVIOWork(KvdoWorkQueue *queue, DataKVIO *dataKVIO) { enqueueKVIOWork(queue, dataKVIOAsKVIO(dataKVIO)); } /** * Add a trace record for the current source location. * * @param dataKVIO The DataKVIO structure to be updated * @param location The source-location descriptor to be recorded **/ static inline void dataKVIOAddTraceRecord(DataKVIO *dataKVIO, TraceLocation location) { dataVIOAddTraceRecord(&dataKVIO->dataVIO, location); } /** * Set up and enqueue a DataKVIO on the CPU queue. * * @param dataKVIO The DataKVIO to set up * @param work The function pointer to execute * @param statsFunction A function pointer to record for stats, or NULL * @param action Action code, mapping to a relative priority **/ static inline void launchDataKVIOOnCPUQueue(DataKVIO *dataKVIO, KvdoWorkFunction work, void *statsFunction, unsigned int action) { KVIO *kvio = dataKVIOAsKVIO(dataKVIO); launchKVIO(kvio, work, statsFunction, action, kvio->layer->cpuQueue); } /** * Set up and enqueue a DataKVIO on the BIO Ack queue. * * @param dataKVIO The DataKVIO to set up * @param work The function pointer to execute * @param statsFunction A function pointer to record for stats, or NULL * @param action Action code, mapping to a relative priority **/ static inline void launchDataKVIOOnBIOAckQueue(DataKVIO *dataKVIO, KvdoWorkFunction work, void *statsFunction, unsigned int action) { KVIO *kvio = dataKVIOAsKVIO(dataKVIO); launchKVIO(kvio, work, statsFunction, action, kvio->layer->bioAckQueue); } /** * Move a DataKVIO back to the base threads. * * @param dataKVIO The DataKVIO to enqueue **/ static inline void kvdoEnqueueDataVIOCallback(DataKVIO *dataKVIO) { kvdoEnqueueVIOCallback(dataKVIOAsKVIO(dataKVIO)); } /** * Check whether the external request bio had FUA set. * * @param dataKVIO The DataKVIO to check * * @return true if the external request bio had FUA set **/ static inline bool requestorSetFUA(DataKVIO *dataKVIO) { return ((dataKVIO->externalIORequest.rw & REQ_FUA) == REQ_FUA); } /** * Associate a KVIO with a BIO passed in from the block layer, and start * processing the KVIO. * * If setting up a KVIO fails, a message is logged, and the limiter permits * (request and maybe discard) released, but the caller is responsible for * disposing of the bio. * * @param layer The physical layer * @param bio The bio for which to create KVIO * @param arrivalTime The time (in jiffies) when the external request * entered the device mapbio function * @param hasDiscardPermit Whether we got a permit from the discardLimiter * of the kernel layer * * @return VDO_SUCCESS or a system error code **/ int kvdoLaunchDataKVIOFromBio(KernelLayer *layer, BIO *bio, Jiffies arrivalTime, bool hasDiscardPermit) __attribute__((warn_unused_result)); /** * Return a batch of DataKVIOs to the pool. * *

Implements BatchProcessorCallback. * * @param batch The batch processor * @param closure The kernal layer **/ void returnDataKVIOBatchToPool(BatchProcessor *batch, void *closure); /** * Implements DataVIOZeroer. * * @param dataVIO The DataVIO to zero **/ void kvdoZeroDataVIO(DataVIO *dataVIO); /** * Implements DataCopier. * * @param source The DataVIO to copy from * @param destination The DataVIO to copy to **/ void kvdoCopyDataVIO(DataVIO *source, DataVIO *destination); /** * Fetch the data for a block from storage. The fetched data will be * uncompressed when the callback is called, and the result of the read * operation will be stored in the ReadBlock's status field. On success, * the data will be in the ReadBlock's data pointer. * * @param dataVIO The DataVIO to read a block in for * @param location The physical block number to read from * @param mappingState The mapping state of the block to read * @param action The bio queue action * @param callback The function to call when the read is done **/ void kvdoReadBlock(DataVIO *dataVIO, PhysicalBlockNumber location, BlockMappingState mappingState, BioQAction action, DataKVIOCallback callback); /** * Implements DataReader. * * @param dataVIO The DataVIO to read **/ void kvdoReadDataVIO(DataVIO *dataVIO); /** * Implements DataWriter. * * @param dataVIO The DataVIO to write **/ void kvdoWriteDataVIO(DataVIO *dataVIO); /** * Implements DataModifier. * * @param dataVIO The DataVIO to modify **/ void kvdoModifyWriteDataVIO(DataVIO *dataVIO); /** * Implements DataHasher. * * @param dataVIO The DataVIO to hash **/ void kvdoHashDataVIO(DataVIO *dataVIO); /** * Implements DuplicationChecker. * * @param dataVIO The DataVIO containing the block to check **/ void kvdoCheckForDuplication(DataVIO *dataVIO); /** * Implements DataAcknowledger. * * @param dataVIO The DataVIO to acknowledge **/ void kvdoAcknowledgeDataVIO(DataVIO *dataVIO); /** * Implements DataCompressor. * * @param dataVIO The DataVIO to compress **/ void kvdoCompressDataVIO(DataVIO *dataVIO); /** * Implements AlbireoUpdater. * * @param dataVIO The DataVIO which needs to change the entry for its data **/ void kvdoUpdateDedupeAdvice(DataVIO *dataVIO); /** * Allocate a buffer pool of DataKVIOs. * * @param [in] layer The layer in which the DataKVIOs will operate * @param [in] poolSize The number of DataKVIOs in the pool * @param [out] bufferPoolPtr A pointer to hold the new buffer pool * * @return VDO_SUCCESS or an error **/ int makeDataKVIOBufferPool(KernelLayer *layer, uint32_t poolSize, BufferPool **bufferPoolPtr) __attribute__((warn_unused_result)); /** * Get the state needed to generate UDS metadata from the DataKVIO * associated with a DedupeContext. * * @param context The DedupeContext * * @return the advice to store in the UDS index **/ DataLocation getDedupeAdvice(const DedupeContext *context) __attribute__((warn_unused_result)); /** * Set the result of a dedupe query for the DataKVIO associated with a * DedupeContext. * * @param context The context receiving advice * @param advice A data location at which the chunk named in the context * might be stored (will be NULL if no advice was found) **/ void setDedupeAdvice(DedupeContext *context, const DataLocation *advice); #endif /* DATA_KVIO_H */