summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/include/PDMBlkCacheInternal.h
blob: ef813e17c4a9784a5c2d41caee5aa1b351159141 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/* $Id: PDMBlkCacheInternal.h $ */
/** @file
 * PDM Block Cache.
 */

/*
 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * 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, in version 3 of the
 * License.
 *
 * 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, see <https://www.gnu.org/licenses>.
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */

#ifndef VMM_INCLUDED_SRC_include_PDMBlkCacheInternal_h
#define VMM_INCLUDED_SRC_include_PDMBlkCacheInternal_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <VBox/vmm/cfgm.h>
#include <VBox/vmm/stam.h>
#include <VBox/vmm/tm.h>
#include <VBox/vmm/pdmblkcache.h>
#include <iprt/types.h>
#include <iprt/file.h>
#include <iprt/thread.h>
#include <iprt/semaphore.h>
#include <iprt/critsect.h>
#include <iprt/avl.h>
#include <iprt/list.h>
#include <iprt/spinlock.h>
#include <iprt/memcache.h>

RT_C_DECLS_BEGIN

/**
 * A few forward declarations.
 */
/** Pointer to a cache LRU list. */
typedef struct PDMBLKLRULIST *PPDMBLKLRULIST;
/** Pointer to the global cache structure. */
typedef struct PDMBLKCACHEGLOBAL *PPDMBLKCACHEGLOBAL;
/** Pointer to a cache entry waiter structure. */
typedef struct PDMBLKCACHEWAITER *PPDMBLKCACHEWAITER;

/**
 * A cache entry
 */
typedef struct PDMBLKCACHEENTRY
{
    /** The AVL entry data. */
    AVLRU64NODECORE                 Core;
    /** Pointer to the previous element. Used in one of the LRU lists.*/
    struct PDMBLKCACHEENTRY        *pPrev;
    /** Pointer to the next element. Used in one of the LRU lists.*/
    struct PDMBLKCACHEENTRY        *pNext;
    /** Pointer to the list the entry is in. */
    PPDMBLKLRULIST                  pList;
    /** Cache the entry belongs to. */
    PPDMBLKCACHE                    pBlkCache;
    /** Flags for this entry. Combinations of PDMACFILECACHE_* \#defines */
    volatile uint32_t               fFlags;
    /** Reference counter. Prevents eviction of the entry if > 0. */
    volatile uint32_t               cRefs;
    /** Size of the entry. */
    uint32_t                        cbData;
    /** Pointer to the memory containing the data. */
    uint8_t                        *pbData;
    /** Head of list of tasks waiting for this one to finish. */
    PPDMBLKCACHEWAITER              pWaitingHead;
    /** Tail of list of tasks waiting for this one to finish. */
    PPDMBLKCACHEWAITER              pWaitingTail;
    /** Node for dirty but not yet committed entries list per endpoint. */
    RTLISTNODE                      NodeNotCommitted;
} PDMBLKCACHEENTRY, *PPDMBLKCACHEENTRY;
/** I/O is still in progress for this entry. This entry is not evictable. */
#define PDMBLKCACHE_ENTRY_IO_IN_PROGRESS RT_BIT(0)
/** Entry is locked and thus not evictable. */
#define PDMBLKCACHE_ENTRY_LOCKED         RT_BIT(1)
/** Entry is dirty */
#define PDMBLKCACHE_ENTRY_IS_DIRTY       RT_BIT(2)
/** Entry is not evictable. */
#define PDMBLKCACHE_NOT_EVICTABLE  (PDMBLKCACHE_ENTRY_LOCKED | PDMBLKCACHE_ENTRY_IO_IN_PROGRESS | PDMBLKCACHE_ENTRY_IS_DIRTY)

/**
 * LRU list data
 */
typedef struct PDMBLKLRULIST
{
    /** Head of the list. */
    PPDMBLKCACHEENTRY pHead;
    /** Tail of the list. */
    PPDMBLKCACHEENTRY pTail;
    /** Number of bytes cached in the list. */
    uint32_t          cbCached;
} PDMBLKLRULIST;

/**
 * Global cache data.
 */
typedef struct PDMBLKCACHEGLOBAL
{
    /** Pointer to the owning VM instance. */
    PVM                 pVM;
    /** Maximum size of the cache in bytes. */
    uint32_t            cbMax;
    /** Current size of the cache in bytes. */
    uint32_t            cbCached;
    /** Critical section protecting the cache. */
    RTCRITSECT          CritSect;
    /** Maximum number of bytes cached. */
    uint32_t            cbRecentlyUsedInMax;
    /** Maximum number of bytes in the paged out list .*/
    uint32_t            cbRecentlyUsedOutMax;
    /** Recently used cache entries list */
    PDMBLKLRULIST       LruRecentlyUsedIn;
    /** Scorecard cache entry list. */
    PDMBLKLRULIST       LruRecentlyUsedOut;
    /** List of frequently used cache entries */
    PDMBLKLRULIST       LruFrequentlyUsed;
    /** Commit timeout in milli seconds */
    uint32_t            u32CommitTimeoutMs;
    /** Number of dirty bytes needed to start a commit of the data to the disk. */
    uint32_t            cbCommitDirtyThreshold;
    /** Current number of dirty bytes in the cache. */
    volatile uint32_t   cbDirty;
    /** Flag whether the VM was suspended becaus of an I/O error. */
    volatile bool       fIoErrorVmSuspended;
    /** Flag whether a commit is currently in progress. */
    volatile bool       fCommitInProgress;
    /** Commit interval timer */
    TMTIMERHANDLE       hTimerCommit;
    /** Number of endpoints using the cache. */
    uint32_t            cRefs;
    /** List of all users of this cache. */
    RTLISTANCHOR        ListUsers;
#ifdef VBOX_WITH_STATISTICS
    /** Hit counter. */
    STAMCOUNTER         cHits;
    /** Partial hit counter. */
    STAMCOUNTER         cPartialHits;
    /** Miss counter. */
    STAMCOUNTER         cMisses;
    /** Bytes read from cache. */
    STAMCOUNTER         StatRead;
    /** Bytes written to the cache. */
    STAMCOUNTER         StatWritten;
    /** Time spend to get an entry in the AVL tree. */
    STAMPROFILEADV      StatTreeGet;
    /** Time spend to insert an entry in the AVL tree. */
    STAMPROFILEADV      StatTreeInsert;
    /** Time spend to remove an entry in the AVL tree. */
    STAMPROFILEADV      StatTreeRemove;
    /** Number of times a buffer could be reused. */
    STAMCOUNTER         StatBuffersReused;
#endif
} PDMBLKCACHEGLOBAL;
#ifdef VBOX_WITH_STATISTICS
AssertCompileMemberAlignment(PDMBLKCACHEGLOBAL, cHits, sizeof(uint64_t));
#endif

/**
 * Block cache type.
 */
typedef enum PDMBLKCACHETYPE
{
    /** Device . */
    PDMBLKCACHETYPE_DEV = 1,
    /** Driver consumer. */
    PDMBLKCACHETYPE_DRV,
    /** Internal consumer. */
    PDMBLKCACHETYPE_INTERNAL,
    /** Usb consumer. */
    PDMBLKCACHETYPE_USB
} PDMBLKCACHETYPE;

/**
 * Per user cache data.
 */
typedef struct PDMBLKCACHE
{
    /** Pointer to the id for the cache. */
    char                         *pszId;
    /** AVL tree managing cache entries. */
    PAVLRU64TREE                  pTree;
    /** R/W semaphore protecting cached entries for this endpoint. */
    RTSEMRW                       SemRWEntries;
    /** Pointer to the gobal cache data */
    PPDMBLKCACHEGLOBAL            pCache;
    /** Lock protecting the dirty entries list. */
    RTSPINLOCK                    LockList;
    /** List of dirty but not committed entries for this endpoint. */
    RTLISTANCHOR                  ListDirtyNotCommitted;
    /** Node of the cache user list. */
    RTLISTNODE                    NodeCacheUser;
    /** Block cache type. */
    PDMBLKCACHETYPE               enmType;
    /** Type specific data. */
    union
    {
        /** PDMASYNCCOMPLETIONTEMPLATETYPE_DEV */
        struct
        {
            /** Pointer to the device instance owning the block cache. */
            R3PTRTYPE(PPDMDEVINS)                            pDevIns;
            /** Complete callback to the user. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERCOMPLETEDEV)         pfnXferComplete;
            /** I/O enqueue callback. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERENQUEUEDEV)          pfnXferEnqueue;
            /** Discard enqueue callback. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERENQUEUEDISCARDDEV)   pfnXferEnqueueDiscard;
        } Dev;
        /** PDMASYNCCOMPLETIONTEMPLATETYPE_DRV */
        struct
        {
            /** Pointer to the driver instance owning the block cache. */
            R3PTRTYPE(PPDMDRVINS)                            pDrvIns;
            /** Complete callback to the user. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERCOMPLETEDRV)         pfnXferComplete;
            /** I/O enqueue callback. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERENQUEUEDRV)          pfnXferEnqueue;
            /** Discard enqueue callback. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV)   pfnXferEnqueueDiscard;
        } Drv;
        /** PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL */
        struct
        {
            /** Pointer to user data. */
            R3PTRTYPE(void *)                                pvUser;
            /** Complete callback to the user. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERCOMPLETEINT)         pfnXferComplete;
            /** I/O enqueue callback. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERENQUEUEINT)          pfnXferEnqueue;
            /** Discard enqueue callback. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERENQUEUEDISCARDINT)   pfnXferEnqueueDiscard;
        } Int;
        /** PDMASYNCCOMPLETIONTEMPLATETYPE_USB */
        struct
        {
            /** Pointer to the usb instance owning the template. */
            R3PTRTYPE(PPDMUSBINS)                            pUsbIns;
            /** Complete callback to the user. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERCOMPLETEUSB)         pfnXferComplete;
            /** I/O enqueue callback. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERENQUEUEUSB)          pfnXferEnqueue;
            /** Discard enqueue callback. */
            R3PTRTYPE(PFNPDMBLKCACHEXFERENQUEUEDISCARDUSB)   pfnXferEnqueueDiscard;
        } Usb;
    } u;

#ifdef VBOX_WITH_STATISTICS

#if HC_ARCH_BITS == 64
    uint32_t                      u32Alignment;
#endif
    /** Number of times a write was deferred because the cache entry was still in progress */
    STAMCOUNTER                   StatWriteDeferred;
    /** Number appended cache entries. */
    STAMCOUNTER                   StatAppendedWrites;
#endif

    /** Flag whether the cache was suspended. */
    volatile bool                 fSuspended;
    /** Number of outstanding I/O transfers. */
    volatile uint32_t             cIoXfersActive;

} PDMBLKCACHE, *PPDMBLKCACHE;
#ifdef VBOX_WITH_STATISTICS
AssertCompileMemberAlignment(PDMBLKCACHE, StatWriteDeferred, sizeof(uint64_t));
#endif

/**
 * I/O task.
 */
typedef struct PDMBLKCACHEREQ
{
    /** Opaque user data returned on completion. */
    void             *pvUser;
    /** Number of pending transfers (waiting for a cache entry and passed through). */
    volatile uint32_t cXfersPending;
    /** Status code. */
    volatile int      rcReq;
} PDMBLKCACHEREQ, *PPDMBLKCACHEREQ;

/**
 * I/O transfer from the cache to the underlying medium.
 */
typedef struct PDMBLKCACHEIOXFER
{
    /** Flag whether the I/O xfer updates a cache entry or updates the request directly. */
    bool                  fIoCache;
    /** Type dependent data. */
    union
    {
        /** Pointer to the entry the transfer updates. */
        PPDMBLKCACHEENTRY pEntry;
        /** Pointer to the request the transfer updates. */
        PPDMBLKCACHEREQ   pReq;
    };
    /** Transfer direction. */
    PDMBLKCACHEXFERDIR    enmXferDir;
    /** Segment used if a cache entry is updated. */
    RTSGSEG               SgSeg;
    /** S/G buffer. */
    RTSGBUF               SgBuf;
} PDMBLKCACHEIOXFER;

/**
 * Cache waiter
 */
typedef struct PDMBLKCACHEWAITER
{
    /* Next waiter in the list. */
    struct PDMBLKCACHEWAITER *pNext;
    /** S/G buffer holding or receiving data. */
    RTSGBUF                   SgBuf;
    /** Offset into the cache entry to start the transfer. */
    uint32_t                  offCacheEntry;
    /** How many bytes to transfer. */
    size_t                    cbTransfer;
    /** Flag whether the task wants to read or write into the entry. */
    bool                      fWrite;
    /** Task the waiter is for. */
    PPDMBLKCACHEREQ           pReq;
} PDMBLKCACHEWAITER;

RT_C_DECLS_END

#endif /* !VMM_INCLUDED_SRC_include_PDMBlkCacheInternal_h */