|
Packit Service |
7e342f |
/*
|
|
Packit Service |
7e342f |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
7e342f |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
7e342f |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
7e342f |
* of the License, or (at your option) any later version.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
7e342f |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
7e342f |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
7e342f |
* GNU General Public License for more details.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
7e342f |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
7e342f |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
7e342f |
* 02110-1301, USA.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/vdoPageCacheInternals.h#8 $
|
|
Packit Service |
7e342f |
*/
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
#ifndef VDO_PAGE_CACHE_INTERNALS_H
|
|
Packit Service |
7e342f |
#define VDO_PAGE_CACHE_INTERNALS_H
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
#include "vdoPageCache.h"
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
#ifndef __KERNEL__
|
|
Packit Service |
7e342f |
# include <stdint.h>
|
|
Packit Service |
7e342f |
#endif
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
#include "blockMapInternals.h"
|
|
Packit Service |
7e342f |
#include "completion.h"
|
|
Packit Service |
7e342f |
#include "dirtyLists.h"
|
|
Packit Service |
7e342f |
#include "intMap.h"
|
|
Packit Service |
7e342f |
#include "physicalLayer.h"
|
|
Packit Service |
7e342f |
#include "ringNode.h"
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
enum {
|
|
Packit Service |
7e342f |
MAX_PAGE_CONTEXT_SIZE = 8,
|
|
Packit Service |
7e342f |
};
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
static const PhysicalBlockNumber NO_PAGE = 0xFFFFFFFFFFFFFFFF;
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**
|
|
Packit Service |
7e342f |
* A PageInfoNode is a ring node.
|
|
Packit Service |
7e342f |
**/
|
|
Packit Service |
7e342f |
typedef RingNode PageInfoNode;
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**
|
|
Packit Service |
7e342f |
* The VDO Page Cache abstraction.
|
|
Packit Service |
7e342f |
**/
|
|
Packit Service |
7e342f |
struct vdoPageCache {
|
|
Packit Service |
7e342f |
/** the physical layer to page to */
|
|
Packit Service |
7e342f |
PhysicalLayer *layer;
|
|
Packit Service |
7e342f |
/** number of pages in cache */
|
|
Packit Service |
7e342f |
PageCount pageCount;
|
|
Packit Service |
7e342f |
/** function to call on page read */
|
|
Packit Service |
7e342f |
VDOPageReadFunction *readHook;
|
|
Packit Service |
7e342f |
/** function to call on page write */
|
|
Packit Service |
7e342f |
VDOPageWriteFunction *writeHook;
|
|
Packit Service |
7e342f |
/** number of pages to write in the current batch */
|
|
Packit Service |
7e342f |
PageCount pagesInBatch;
|
|
Packit Service |
7e342f |
/** Whether the VDO is doing a read-only rebuild */
|
|
Packit Service |
7e342f |
bool rebuilding;
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/** array of page information entries */
|
|
Packit Service |
7e342f |
PageInfo *infos;
|
|
Packit Service |
7e342f |
/** raw memory for pages */
|
|
Packit Service |
7e342f |
char *pages;
|
|
Packit Service |
7e342f |
/** cache last found page info */
|
|
Packit Service |
7e342f |
PageInfo *lastFound;
|
|
Packit Service |
7e342f |
/** map of page number to info */
|
|
Packit Service |
7e342f |
IntMap *pageMap;
|
|
Packit Service |
7e342f |
/** master LRU list (all infos) */
|
|
Packit Service |
7e342f |
PageInfoNode lruList;
|
|
Packit Service |
7e342f |
/** dirty pages by period */
|
|
Packit Service |
7e342f |
DirtyLists *dirtyLists;
|
|
Packit Service |
7e342f |
/** free page list (oldest first) */
|
|
Packit Service |
7e342f |
PageInfoNode freeList;
|
|
Packit Service |
7e342f |
/** outgoing page list */
|
|
Packit Service |
7e342f |
PageInfoNode outgoingList;
|
|
Packit Service |
7e342f |
/** number of read I/O operations pending */
|
|
Packit Service |
7e342f |
PageCount outstandingReads;
|
|
Packit Service |
7e342f |
/** number of write I/O operations pending */
|
|
Packit Service |
7e342f |
PageCount outstandingWrites;
|
|
Packit Service |
7e342f |
/** number of pages covered by the current flush */
|
|
Packit Service |
7e342f |
PageCount pagesInFlush;
|
|
Packit Service |
7e342f |
/** number of pages waiting to be included in the next flush */
|
|
Packit Service |
7e342f |
PageCount pagesToFlush;
|
|
Packit Service |
7e342f |
/** number of discards in progress */
|
|
Packit Service |
7e342f |
unsigned int discardCount;
|
|
Packit Service |
7e342f |
/** how many VPCs waiting for free page */
|
|
Packit Service |
7e342f |
unsigned int waiterCount;
|
|
Packit Service |
7e342f |
/** queue of waiters who want a free page */
|
|
Packit Service |
7e342f |
WaitQueue freeWaiters;
|
|
Packit Service |
7e342f |
/** statistics */
|
|
Packit Service |
7e342f |
AtomicPageCacheStatistics stats;
|
|
Packit Service |
7e342f |
/** counter for pressure reports */
|
|
Packit Service |
7e342f |
uint32_t pressureReport;
|
|
Packit Service |
7e342f |
/** the block map zone to which this cache belongs */
|
|
Packit Service |
7e342f |
BlockMapZone *zone;
|
|
Packit Service |
7e342f |
};
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**
|
|
Packit Service |
7e342f |
* The state of a page buffer. If the page buffer is free no particular page is
|
|
Packit Service |
7e342f |
* bound to it, otherwise the page buffer is bound to particular page whose
|
|
Packit Service |
7e342f |
* absolute pbn is in the pbn field. If the page is resident or dirty the page
|
|
Packit Service |
7e342f |
* data is stable and may be accessed. Otherwise the page is in flight
|
|
Packit Service |
7e342f |
* (incoming or outgoing) and its data should not be accessed.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* @note Update the static data in vpcPageStateName() and vpcPageStateFlag()
|
|
Packit Service |
7e342f |
* if you change this enumeration.
|
|
Packit Service |
7e342f |
**/
|
|
Packit Service |
7e342f |
typedef enum __attribute__((packed)) pageState {
|
|
Packit Service |
7e342f |
/* this page buffer is not being used */
|
|
Packit Service |
7e342f |
PS_FREE,
|
|
Packit Service |
7e342f |
/* this page is being read from store */
|
|
Packit Service |
7e342f |
PS_INCOMING,
|
|
Packit Service |
7e342f |
/* attempt to load this page failed */
|
|
Packit Service |
7e342f |
PS_FAILED,
|
|
Packit Service |
7e342f |
/* this page is valid and un-modified */
|
|
Packit Service |
7e342f |
PS_RESIDENT,
|
|
Packit Service |
7e342f |
/* this page is valid and modified */
|
|
Packit Service |
7e342f |
PS_DIRTY,
|
|
Packit Service |
7e342f |
/* this page is being written and should not be used */
|
|
Packit Service |
7e342f |
PS_OUTGOING,
|
|
Packit Service |
7e342f |
/* not a state */
|
|
Packit Service |
7e342f |
PAGE_STATE_COUNT,
|
|
Packit Service |
7e342f |
} PageState;
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**
|
|
Packit Service |
7e342f |
* The write status of page
|
|
Packit Service |
7e342f |
**/
|
|
Packit Service |
7e342f |
typedef enum __attribute__((packed)) {
|
|
Packit Service |
7e342f |
WRITE_STATUS_NORMAL,
|
|
Packit Service |
7e342f |
WRITE_STATUS_DISCARD,
|
|
Packit Service |
7e342f |
WRITE_STATUS_DEFERRED,
|
|
Packit Service |
7e342f |
} WriteStatus;
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**
|
|
Packit Service |
7e342f |
* Per-page-slot information.
|
|
Packit Service |
7e342f |
**/
|
|
Packit Service |
7e342f |
struct pageInfo {
|
|
Packit Service |
7e342f |
/** Preallocated page VIO */
|
|
Packit Service |
7e342f |
VIO *vio;
|
|
Packit Service |
7e342f |
/** back-link for references */
|
|
Packit Service |
7e342f |
VDOPageCache *cache;
|
|
Packit Service |
7e342f |
/** the pbn of the page */
|
|
Packit Service |
7e342f |
PhysicalBlockNumber pbn;
|
|
Packit Service |
7e342f |
/** page is busy (temporarily locked) */
|
|
Packit Service |
7e342f |
uint16_t busy;
|
|
Packit Service |
7e342f |
/** the write status the page */
|
|
Packit Service |
7e342f |
WriteStatus writeStatus;
|
|
Packit Service |
7e342f |
/** page state */
|
|
Packit Service |
7e342f |
PageState state;
|
|
Packit Service |
7e342f |
/** queue of completions awaiting this item */
|
|
Packit Service |
7e342f |
WaitQueue waiting;
|
|
Packit Service |
7e342f |
/** state linked list node */
|
|
Packit Service |
7e342f |
PageInfoNode listNode;
|
|
Packit Service |
7e342f |
/** LRU node */
|
|
Packit Service |
7e342f |
PageInfoNode lruNode;
|
|
Packit Service |
7e342f |
/** Space for per-page client data */
|
|
Packit Service |
7e342f |
byte context[MAX_PAGE_CONTEXT_SIZE];
|
|
Packit Service |
7e342f |
};
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
// PAGE INFO LIST OPERATIONS
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline PageInfo *pageInfoFromListNode(PageInfoNode *node)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
if (node == NULL) {
|
|
Packit Service |
7e342f |
return NULL;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
return (PageInfo *) ((uintptr_t) node - offsetof(PageInfo, listNode));
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline PageInfo *pageInfoFromLRUNode(PageInfoNode *node)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
if (node == NULL) {
|
|
Packit Service |
7e342f |
return NULL;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
return (PageInfo *) ((uintptr_t) node - offsetof(PageInfo, lruNode));
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
// PAGE INFO STATE ACCESSOR FUNCTIONS
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline bool isFree(const PageInfo *info)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
return info->state == PS_FREE;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline bool isAvailable(const PageInfo *info)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
return (info->state == PS_FREE) || (info->state == PS_FAILED);
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline bool isPresent(const PageInfo *info)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
return (info->state == PS_RESIDENT) || (info->state == PS_DIRTY);
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline bool isDirty(const PageInfo *info)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
return info->state == PS_DIRTY;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline bool isResident(const PageInfo *info)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
return info->state == PS_RESIDENT;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline bool isInFlight(const PageInfo *info)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
return (info->state == PS_INCOMING) || (info->state == PS_OUTGOING);
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline bool isIncoming(const PageInfo *info)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
return info->state == PS_INCOMING;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline bool isOutgoing(const PageInfo *info)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
return info->state == PS_OUTGOING;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline bool isValid(const PageInfo *info)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
return isPresent(info) || isOutgoing(info);
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
// COMPLETION CONVERSIONS
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline VDOPageCompletion *asVDOPageCompletion(VDOCompletion *completion)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
assertCompletionType(completion->type, VDO_PAGE_COMPLETION);
|
|
Packit Service |
7e342f |
return (VDOPageCompletion *) ((uintptr_t) completion
|
|
Packit Service |
7e342f |
- offsetof(VDOPageCompletion, completion));
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**********************************************************************/
|
|
Packit Service |
7e342f |
static inline
|
|
Packit Service |
7e342f |
VDOPageCompletion *pageCompletionFromWaiter(Waiter *waiter)
|
|
Packit Service |
7e342f |
{
|
|
Packit Service |
7e342f |
if (waiter == NULL) {
|
|
Packit Service |
7e342f |
return NULL;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
VDOPageCompletion *completion = (VDOPageCompletion *)
|
|
Packit Service |
7e342f |
((uintptr_t) waiter - offsetof(VDOPageCompletion, waiter));
|
|
Packit Service |
7e342f |
assertCompletionType(completion->completion.type, VDO_PAGE_COMPLETION);
|
|
Packit Service |
7e342f |
return completion;
|
|
Packit Service |
7e342f |
}
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
// COMMONLY USED FUNCTIONS
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
// All of these functions are prefixed "vpc" in order to prevent namespace
|
|
Packit Service |
7e342f |
// issues (ordinarily they would be static).
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**
|
|
Packit Service |
7e342f |
* Find the page info (if any) associated with a given pbn.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* @param cache the page cache
|
|
Packit Service |
7e342f |
* @param pbn the absolute physical block number of the page
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* @return the page info for the page if available, or NULL if not
|
|
Packit Service |
7e342f |
**/
|
|
Packit Service |
7e342f |
PageInfo *vpcFindPage(VDOPageCache *cache, PhysicalBlockNumber pbn)
|
|
Packit Service |
7e342f |
__attribute__((warn_unused_result));
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
/**
|
|
Packit Service |
7e342f |
* Return the name of a page state.
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* @param state a page state
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* @return a pointer to a static page state name
|
|
Packit Service |
7e342f |
*
|
|
Packit Service |
7e342f |
* @note If the page state is invalid a static string is returned and the
|
|
Packit Service |
7e342f |
* invalid state is logged.
|
|
Packit Service |
7e342f |
**/
|
|
Packit Service |
7e342f |
const char *vpcPageStateName(PageState state)
|
|
Packit Service |
7e342f |
__attribute__((warn_unused_result));
|
|
Packit Service |
7e342f |
|
|
Packit Service |
7e342f |
#endif // VDO_PAGE_CACHE_INTERNALS_H
|