VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp@ 63689

Last change on this file since 63689 was 63689, checked in by vboxsync, 9 years ago

Storage: New ramdisk driver for debugging and make DrvDiskIntegrity compile with warnings as errors enabled

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 54.2 KB
Line 
1/* $Id: DrvDiskIntegrity.cpp 63689 2016-09-02 12:00:03Z vboxsync $ */
2/** @file
3 * VBox storage devices: Disk integrity check.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_DISK_INTEGRITY
23#include <VBox/vmm/pdmdrv.h>
24#include <VBox/vmm/pdmstorageifs.h>
25#include <VBox/vddbg.h>
26#include <iprt/assert.h>
27#include <iprt/string.h>
28#include <iprt/uuid.h>
29#include <iprt/avl.h>
30#include <iprt/mem.h>
31#include <iprt/message.h>
32#include <iprt/sg.h>
33#include <iprt/time.h>
34#include <iprt/semaphore.h>
35#include <iprt/asm.h>
36
37#include "VBoxDD.h"
38
39
40/*********************************************************************************************************************************
41* Structures and Typedefs *
42*********************************************************************************************************************************/
43
44/**
45 * Transfer direction.
46 */
47typedef enum DRVDISKAIOTXDIR
48{
49 /** Read */
50 DRVDISKAIOTXDIR_READ = 0,
51 /** Write */
52 DRVDISKAIOTXDIR_WRITE,
53 /** Flush */
54 DRVDISKAIOTXDIR_FLUSH,
55 /** Discard */
56 DRVDISKAIOTXDIR_DISCARD,
57 /** Read after write for immediate verification. */
58 DRVDISKAIOTXDIR_READ_AFTER_WRITE
59} DRVDISKAIOTXDIR;
60
61/**
62 * async I/O request.
63 */
64typedef struct DRVDISKAIOREQ
65{
66 /** Transfer direction. */
67 DRVDISKAIOTXDIR enmTxDir;
68 /** Start offset. */
69 uint64_t off;
70 /** Transfer size. */
71 size_t cbTransfer;
72 /** Segment array. */
73 PCRTSGSEG paSeg;
74 /** Number of array entries. */
75 unsigned cSeg;
76 /** User argument */
77 void *pvUser;
78 /** Slot in the array. */
79 unsigned iSlot;
80 /** Start timestamp */
81 uint64_t tsStart;
82 /** Completion timestamp. */
83 uint64_t tsComplete;
84 /** I/O log entry if configured. */
85 VDIOLOGENT hIoLogEntry;
86 /** Ranges to discard. */
87 PCRTRANGE paRanges;
88 /** Number of ranges. */
89 unsigned cRanges;
90} DRVDISKAIOREQ, *PDRVDISKAIOREQ;
91
92/**
93 * I/O log entry.
94 */
95typedef struct IOLOGENT
96{
97 /** Start offset */
98 uint64_t off;
99 /** Write size */
100 size_t cbWrite;
101 /** Number of references to this entry. */
102 unsigned cRefs;
103} IOLOGENT, *PIOLOGENT;
104
105/**
106 * Disk segment.
107 */
108typedef struct DRVDISKSEGMENT
109{
110 /** AVL core. */
111 AVLRFOFFNODECORE Core;
112 /** Size of the segment */
113 size_t cbSeg;
114 /** Data for this segment */
115 uint8_t *pbSeg;
116 /** Number of entries in the I/O array. */
117 unsigned cIoLogEntries;
118 /** Array of I/O log references. */
119 PIOLOGENT apIoLog[1];
120} DRVDISKSEGMENT, *PDRVDISKSEGMENT;
121
122/**
123 * Active requests list entry.
124 */
125typedef struct DRVDISKAIOREQACTIVE
126{
127 /** Pointer to the request. */
128 volatile PDRVDISKAIOREQ pIoReq;
129 /** Start timestamp. */
130 uint64_t tsStart;
131} DRVDISKAIOREQACTIVE, *PDRVDISKAIOREQACTIVE;
132
133/**
134 * Disk integrity driver instance data.
135 *
136 * @implements PDMIMEDIA
137 */
138typedef struct DRVDISKINTEGRITY
139{
140 /** Pointer driver instance. */
141 PPDMDRVINS pDrvIns;
142 /** Pointer to the media driver below us.
143 * This is NULL if the media is not mounted. */
144 PPDMIMEDIA pDrvMedia;
145 /** Our media interface */
146 PDMIMEDIA IMedia;
147
148 /** The media port interface above. */
149 PPDMIMEDIAPORT pDrvMediaPort;
150 /** Media port interface */
151 PDMIMEDIAPORT IMediaPort;
152
153 /** Pointer to the media async driver below us.
154 * This is NULL if the media is not mounted. */
155 PPDMIMEDIAASYNC pDrvMediaAsync;
156 /** Our media async interface */
157 PDMIMEDIAASYNC IMediaAsync;
158
159 /** The async media port interface above. */
160 PPDMIMEDIAASYNCPORT pDrvMediaAsyncPort;
161 /** Our media async port interface */
162 PDMIMEDIAASYNCPORT IMediaAsyncPort;
163
164 /** Flag whether consistency checks are enabled. */
165 bool fCheckConsistency;
166 /** Flag whether the RAM disk was prepopulated. */
167 bool fPrepopulateRamDisk;
168 /** AVL tree containing the disk blocks to check. */
169 PAVLRFOFFTREE pTreeSegments;
170
171 /** Flag whether async request tracing is enabled. */
172 bool fTraceRequests;
173 /** Interval the thread should check for expired requests (milliseconds). */
174 uint32_t uCheckIntervalMs;
175 /** Expire timeout for a request (milliseconds). */
176 uint32_t uExpireIntervalMs;
177 /** Thread which checks for lost requests. */
178 RTTHREAD hThread;
179 /** Event semaphore */
180 RTSEMEVENT SemEvent;
181 /** Flag whether the thread should run. */
182 bool fRunning;
183 /** Array containing active requests. */
184 DRVDISKAIOREQACTIVE apReqActive[128];
185 /** Next free slot in the array */
186 volatile unsigned iNextFreeSlot;
187
188 /** Flag whether we check for requests completing twice. */
189 bool fCheckDoubleCompletion;
190 /** Number of requests we go back. */
191 unsigned cEntries;
192 /** Array of completed but still observed requests. */
193 PDRVDISKAIOREQ *papIoReq;
194 /** Current entry in the array. */
195 unsigned iEntry;
196
197 /** Flag whether to do a immediate read after write for verification. */
198 bool fReadAfterWrite;
199 /** Flag whether to record the data to write before the write completed successfully.
200 * Useful in case the data is modified in place later on (encryption for instance). */
201 bool fRecordWriteBeforeCompletion;
202
203 /** I/O logger to use if enabled. */
204 VDIOLOGGER hIoLogger;
205} DRVDISKINTEGRITY, *PDRVDISKINTEGRITY;
206
207
208/**
209 * Allocate a new I/O request.
210 *
211 * @returns New I/O request.
212 * @param enmTxDir Transfer direction.
213 * @param off Start offset.
214 * @param paSeg Segment array.
215 * @param cSeg Number of segments.
216 * @param cbTransfer Number of bytes to transfer.
217 * @param pvUser User argument.
218 */
219static PDRVDISKAIOREQ drvdiskintIoReqAlloc(DRVDISKAIOTXDIR enmTxDir, uint64_t off, PCRTSGSEG paSeg,
220 unsigned cSeg, size_t cbTransfer, void *pvUser)
221{
222 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)RTMemAlloc(sizeof(DRVDISKAIOREQ));
223
224 if (RT_LIKELY(pIoReq))
225 {
226 pIoReq->enmTxDir = enmTxDir;
227 pIoReq->off = off;
228 pIoReq->cbTransfer = cbTransfer;
229 pIoReq->paSeg = paSeg;
230 pIoReq->cSeg = cSeg;
231 pIoReq->pvUser = pvUser;
232 pIoReq->iSlot = 0;
233 pIoReq->tsStart = RTTimeSystemMilliTS();
234 pIoReq->tsComplete = 0;
235 pIoReq->hIoLogEntry = NULL;
236 }
237
238 return pIoReq;
239}
240
241/**
242 * Free a async I/O request.
243 *
244 * @returns nothing.
245 * @param pThis Disk driver.
246 * @param pIoReq The I/O request to free.
247 */
248static void drvdiskintIoReqFree(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
249{
250 if (pThis->fCheckDoubleCompletion)
251 {
252 /* Search if the I/O request completed already. */
253 for (unsigned i = 0; i < pThis->cEntries; i++)
254 {
255 if (RT_UNLIKELY(pThis->papIoReq[i] == pIoReq))
256 {
257 RTMsgError("Request %#p completed already!\n", pIoReq);
258 RTMsgError("Start timestamp %llu Completion timestamp %llu (completed after %llu ms)\n",
259 pIoReq->tsStart, pIoReq->tsComplete, pIoReq->tsComplete - pIoReq->tsStart);
260 RTAssertDebugBreak();
261 }
262 }
263
264 pIoReq->tsComplete = RTTimeSystemMilliTS();
265 Assert(!pThis->papIoReq[pThis->iEntry]);
266 pThis->papIoReq[pThis->iEntry] = pIoReq;
267
268 pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
269 if (pThis->papIoReq[pThis->iEntry])
270 {
271 RTMemFree(pThis->papIoReq[pThis->iEntry]);
272 pThis->papIoReq[pThis->iEntry] = NULL;
273 }
274 }
275 else
276 RTMemFree(pIoReq);
277}
278
279static void drvdiskintIoLogEntryRelease(PIOLOGENT pIoLogEnt)
280{
281 pIoLogEnt->cRefs--;
282 if (!pIoLogEnt->cRefs)
283 RTMemFree(pIoLogEnt);
284}
285
286/**
287 * Record a successful write to the virtual disk.
288 *
289 * @returns VBox status code.
290 * @param pThis Disk integrity driver instance data.
291 * @param paSeg Segment array of the write to record.
292 * @param cSeg Number of segments.
293 * @param off Start offset.
294 * @param cbWrite Number of bytes to record.
295 */
296static int drvdiskintWriteRecord(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
297 uint64_t off, size_t cbWrite)
298{
299 int rc = VINF_SUCCESS;
300
301 LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbWrite=%u\n",
302 pThis, paSeg, cSeg, off, cbWrite));
303
304 /* Update the segments */
305 size_t cbLeft = cbWrite;
306 RTFOFF offCurr = (RTFOFF)off;
307 RTSGBUF SgBuf;
308 PIOLOGENT pIoLogEnt = (PIOLOGENT)RTMemAllocZ(sizeof(IOLOGENT));
309 if (!pIoLogEnt)
310 return VERR_NO_MEMORY;
311
312 pIoLogEnt->off = off;
313 pIoLogEnt->cbWrite = cbWrite;
314 pIoLogEnt->cRefs = 0;
315
316 RTSgBufInit(&SgBuf, paSeg, cSeg);
317
318 while (cbLeft)
319 {
320 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
321 size_t cbRange = 0;
322 bool fSet = false;
323 unsigned offSeg = 0;
324
325 if (!pSeg)
326 {
327 /* Get next segment */
328 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
329 if ( !pSeg
330 || offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
331 cbRange = cbLeft;
332 else
333 cbRange = pSeg->Core.Key - offCurr;
334
335 Assert(cbRange % 512 == 0);
336
337 /* Create new segment */
338 pSeg = (PDRVDISKSEGMENT)RTMemAllocZ(RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbRange / 512]));
339 if (pSeg)
340 {
341 pSeg->Core.Key = offCurr;
342 pSeg->Core.KeyLast = offCurr + (RTFOFF)cbRange - 1;
343 pSeg->cbSeg = cbRange;
344 pSeg->pbSeg = (uint8_t *)RTMemAllocZ(cbRange);
345 pSeg->cIoLogEntries = cbRange / 512;
346 if (!pSeg->pbSeg)
347 RTMemFree(pSeg);
348 else
349 {
350 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
351 AssertMsg(fInserted, ("Bug!\n"));
352 fSet = true;
353 }
354 }
355 }
356 else
357 {
358 fSet = true;
359 offSeg = offCurr - pSeg->Core.Key;
360 cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
361 }
362
363 if (fSet)
364 {
365 AssertPtr(pSeg);
366 size_t cbCopied = RTSgBufCopyToBuf(&SgBuf, pSeg->pbSeg + offSeg, cbRange);
367 Assert(cbCopied == cbRange);
368
369 /* Update the I/O log pointers */
370 Assert(offSeg % 512 == 0);
371 Assert(cbRange % 512 == 0);
372 while (offSeg < cbRange)
373 {
374 uint32_t uSector = offSeg / 512;
375 PIOLOGENT pIoLogOld = NULL;
376
377 AssertMsg(uSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
378
379 pIoLogOld = pSeg->apIoLog[uSector];
380 if (pIoLogOld)
381 {
382 pIoLogOld->cRefs--;
383 if (!pIoLogOld->cRefs)
384 RTMemFree(pIoLogOld);
385 }
386
387 pSeg->apIoLog[uSector] = pIoLogEnt;
388 pIoLogEnt->cRefs++;
389
390 offSeg += 512;
391 }
392 }
393 else
394 RTSgBufAdvance(&SgBuf, cbRange);
395
396 offCurr += cbRange;
397 cbLeft -= cbRange;
398 }
399
400 return rc;
401}
402
403/**
404 * Verifies a read request.
405 *
406 * @returns VBox status code.
407 * @param pThis Disk integrity driver instance data.
408 * @param paSeg Segment array of the containing the data buffers to verify.
409 * @param cSeg Number of segments.
410 * @param off Start offset.
411 * @param cbWrite Number of bytes to verify.
412 */
413static int drvdiskintReadVerify(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
414 uint64_t off, size_t cbRead)
415{
416 int rc = VINF_SUCCESS;
417
418 LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbRead=%u\n",
419 pThis, paSeg, cSeg, off, cbRead));
420
421 Assert(off % 512 == 0);
422 Assert(cbRead % 512 == 0);
423
424 /* Compare read data */
425 size_t cbLeft = cbRead;
426 RTFOFF offCurr = (RTFOFF)off;
427 RTSGBUF SgBuf;
428
429 RTSgBufInit(&SgBuf, paSeg, cSeg);
430
431 while (cbLeft)
432 {
433 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
434 size_t cbRange = 0;
435 bool fCmp = false;
436 unsigned offSeg = 0;
437
438 if (!pSeg)
439 {
440 /* Get next segment */
441 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
442 if (!pSeg)
443 {
444 /* No data in the tree for this read. Assume everything is ok. */
445 cbRange = cbLeft;
446 }
447 else if (offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
448 cbRange = cbLeft;
449 else
450 cbRange = pSeg->Core.Key - offCurr;
451
452 if (pThis->fPrepopulateRamDisk)
453 {
454 /* No segment means everything should be 0 for this part. */
455 if (!RTSgBufIsZero(&SgBuf, cbRange))
456 {
457 RTMsgError("Corrupted disk at offset %llu (expected everything to be 0)!\n",
458 offCurr);
459 RTAssertDebugBreak();
460 }
461 }
462 }
463 else
464 {
465 fCmp = true;
466 offSeg = offCurr - pSeg->Core.Key;
467 cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
468 }
469
470 if (fCmp)
471 {
472 RTSGSEG Seg;
473 RTSGBUF SgBufCmp;
474 size_t cbOff = 0;
475
476 Seg.cbSeg = cbRange;
477 Seg.pvSeg = pSeg->pbSeg + offSeg;
478
479 RTSgBufInit(&SgBufCmp, &Seg, 1);
480 if (RTSgBufCmpEx(&SgBuf, &SgBufCmp, cbRange, &cbOff, true))
481 {
482 /* Corrupted disk, print I/O log entry of the last write which accessed this range. */
483 uint32_t cSector = (offSeg + cbOff) / 512;
484 AssertMsg(cSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
485
486 RTMsgError("Corrupted disk at offset %llu (%u bytes in the current read buffer)!\n",
487 offCurr + cbOff, cbOff);
488 RTMsgError("Last write to this sector started at offset %llu with %u bytes (%u references to this log entry)\n",
489 pSeg->apIoLog[cSector]->off,
490 pSeg->apIoLog[cSector]->cbWrite,
491 pSeg->apIoLog[cSector]->cRefs);
492 RTAssertDebugBreak();
493 }
494 }
495 else
496 RTSgBufAdvance(&SgBuf, cbRange);
497
498 offCurr += cbRange;
499 cbLeft -= cbRange;
500 }
501
502 return rc;
503}
504
505/**
506 * Discards the given ranges from the disk.
507 *
508 * @returns VBox status code.
509 * @param pThis Disk integrity driver instance data.
510 * @param paRanges Array of ranges to discard.
511 * @param cRanges Number of ranges in the array.
512 */
513static int drvdiskintDiscardRecords(PDRVDISKINTEGRITY pThis, PCRTRANGE paRanges, unsigned cRanges)
514{
515 int rc = VINF_SUCCESS;
516
517 LogFlowFunc(("pThis=%#p paRanges=%#p cRanges=%u\n", pThis, paRanges, cRanges));
518
519 for (unsigned i = 0; i < cRanges; i++)
520 {
521 uint64_t offStart = paRanges[i].offStart;
522 size_t cbLeft = paRanges[i].cbRange;
523
524 LogFlowFunc(("Discarding off=%llu cbRange=%zu\n", offStart, cbLeft));
525
526 while (cbLeft)
527 {
528 size_t cbRange;
529 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offStart);
530
531 if (!pSeg)
532 {
533 /* Get next segment */
534 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offStart, true);
535 if ( !pSeg
536 || (RTFOFF)offStart + (RTFOFF)cbLeft <= pSeg->Core.Key)
537 cbRange = cbLeft;
538 else
539 cbRange = pSeg->Core.Key - offStart;
540
541 Assert(!(cbRange % 512));
542 }
543 else
544 {
545 size_t cbPreLeft, cbPostLeft;
546
547 cbRange = RT_MIN(cbLeft, pSeg->Core.KeyLast - offStart + 1);
548 cbPreLeft = offStart - pSeg->Core.Key;
549 cbPostLeft = pSeg->cbSeg - cbRange - cbPreLeft;
550
551 Assert(!(cbRange % 512));
552 Assert(!(cbPreLeft % 512));
553 Assert(!(cbPostLeft % 512));
554
555 LogFlowFunc(("cbRange=%zu cbPreLeft=%zu cbPostLeft=%zu\n",
556 cbRange, cbPreLeft, cbPostLeft));
557
558 RTAvlrFileOffsetRemove(pThis->pTreeSegments, pSeg->Core.Key);
559
560 if (!cbPreLeft && !cbPostLeft)
561 {
562 /* Just free the whole segment. */
563 LogFlowFunc(("Freeing whole segment pSeg=%#p\n", pSeg));
564 RTMemFree(pSeg->pbSeg);
565 for (unsigned idx = 0; idx < pSeg->cIoLogEntries; idx++)
566 drvdiskintIoLogEntryRelease(pSeg->apIoLog[idx]);
567 RTMemFree(pSeg);
568 }
569 else if (cbPreLeft && !cbPostLeft)
570 {
571 /* Realloc to new size and insert. */
572 LogFlowFunc(("Realloc segment pSeg=%#p\n", pSeg));
573 pSeg->pbSeg = (uint8_t *)RTMemRealloc(pSeg->pbSeg, cbPreLeft);
574 for (unsigned idx = cbPreLeft / 512; idx < pSeg->cIoLogEntries; idx++)
575 drvdiskintIoLogEntryRelease(pSeg->apIoLog[idx]);
576 pSeg = (PDRVDISKSEGMENT)RTMemRealloc(pSeg, RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbPreLeft / 512]));
577 pSeg->Core.KeyLast = pSeg->Core.Key + cbPreLeft - 1;
578 pSeg->cbSeg = cbPreLeft;
579 pSeg->cIoLogEntries = cbPreLeft / 512;
580 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
581 Assert(fInserted);
582 }
583 else if (!cbPreLeft && cbPostLeft)
584 {
585 /* Move data to the front and realloc. */
586 LogFlowFunc(("Move data and realloc segment pSeg=%#p\n", pSeg));
587 memmove(pSeg->pbSeg, pSeg->pbSeg + cbRange, cbPostLeft);
588 for (unsigned idx = 0; idx < cbRange / 512; idx++)
589 drvdiskintIoLogEntryRelease(pSeg->apIoLog[idx]);
590 for (unsigned idx = 0; idx < cbPostLeft /512; idx++)
591 pSeg->apIoLog[idx] = pSeg->apIoLog[(cbRange / 512) + idx];
592 pSeg = (PDRVDISKSEGMENT)RTMemRealloc(pSeg, RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbPostLeft / 512]));
593 pSeg->pbSeg = (uint8_t *)RTMemRealloc(pSeg->pbSeg, cbPostLeft);
594 pSeg->Core.Key += cbRange;
595 pSeg->cbSeg = cbPostLeft;
596 pSeg->cIoLogEntries = cbPostLeft / 512;
597 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
598 Assert(fInserted);
599 }
600 else
601 {
602 /* Split the segment into 2 new segments. */
603 LogFlowFunc(("Split segment pSeg=%#p\n", pSeg));
604 PDRVDISKSEGMENT pSegPost = (PDRVDISKSEGMENT)RTMemAllocZ(RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbPostLeft / 512]));
605 if (pSegPost)
606 {
607 pSegPost->Core.Key = pSeg->Core.Key + cbPreLeft + cbRange;
608 pSegPost->Core.KeyLast = pSeg->Core.KeyLast;
609 pSegPost->cbSeg = cbPostLeft;
610 pSegPost->pbSeg = (uint8_t *)RTMemAllocZ(cbPostLeft);
611 pSegPost->cIoLogEntries = cbPostLeft / 512;
612 if (!pSegPost->pbSeg)
613 RTMemFree(pSegPost);
614 else
615 {
616 memcpy(pSegPost->pbSeg, pSeg->pbSeg + cbPreLeft + cbRange, cbPostLeft);
617 for (unsigned idx = 0; idx < cbPostLeft / 512; idx++)
618 pSegPost->apIoLog[idx] = pSeg->apIoLog[((cbPreLeft + cbRange) / 512) + idx];
619
620 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSegPost->Core);
621 Assert(fInserted);
622 }
623 }
624
625 /* Shrink the current segment. */
626 pSeg->pbSeg = (uint8_t *)RTMemRealloc(pSeg->pbSeg, cbPreLeft);
627 for (unsigned idx = cbPreLeft / 512; idx < (cbPreLeft + cbRange) / 512; idx++)
628 drvdiskintIoLogEntryRelease(pSeg->apIoLog[idx]);
629 pSeg = (PDRVDISKSEGMENT)RTMemRealloc(pSeg, RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbPreLeft / 512]));
630 pSeg->Core.KeyLast = pSeg->Core.Key + cbPreLeft - 1;
631 pSeg->cbSeg = cbPreLeft;
632 pSeg->cIoLogEntries = cbPreLeft / 512;
633 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
634 Assert(fInserted);
635 } /* if (cbPreLeft && cbPostLeft) */
636 }
637
638 offStart += cbRange;
639 cbLeft -= cbRange;
640 }
641 }
642
643 LogFlowFunc(("returns rc=%Rrc\n", rc));
644 return rc;
645}
646
647/**
648 * Adds a request to the active list.
649 *
650 * @returns nothing.
651 * @param pThis The driver instance data.
652 * @param pIoReq The request to add.
653 */
654static void drvdiskintIoReqAdd(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
655{
656 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pThis->iNextFreeSlot];
657
658 Assert(!pReqActive->pIoReq);
659 pReqActive->tsStart = pIoReq->tsStart;
660 pReqActive->pIoReq = pIoReq;
661 pIoReq->iSlot = pThis->iNextFreeSlot;
662
663 /* Search for the next one. */
664 while (pThis->apReqActive[pThis->iNextFreeSlot].pIoReq)
665 pThis->iNextFreeSlot = (pThis->iNextFreeSlot+1) % RT_ELEMENTS(pThis->apReqActive);
666}
667
668/**
669 * Removes a request from the active list.
670 *
671 * @returns nothing.
672 * @param pThis The driver instance data.
673 * @param pIoReq The request to remove.
674 */
675static void drvdiskintIoReqRemove(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
676{
677 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pIoReq->iSlot];
678
679 Assert(pReqActive->pIoReq == pIoReq);
680
681 ASMAtomicWriteNullPtr(&pReqActive->pIoReq);
682}
683
684/**
685 * Thread checking for expired requests.
686 *
687 * @returns IPRT status code.
688 * @param pThread Thread handle.
689 * @param pvUser Opaque user data.
690 */
691static DECLCALLBACK(int) drvdiskIntIoReqExpiredCheck(RTTHREAD pThread, void *pvUser)
692{
693 PDRVDISKINTEGRITY pThis = (PDRVDISKINTEGRITY)pvUser;
694
695 RT_NOREF(pThread);
696
697 while (pThis->fRunning)
698 {
699 int rc = RTSemEventWait(pThis->SemEvent, pThis->uCheckIntervalMs);
700
701 if (!pThis->fRunning)
702 break;
703
704 Assert(rc == VERR_TIMEOUT);
705
706 /* Get current timestamp for comparison. */
707 uint64_t tsCurr = RTTimeSystemMilliTS();
708
709 /* Go through the array and check for expired requests. */
710 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
711 {
712 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[i];
713 PDRVDISKAIOREQ pIoReq = ASMAtomicReadPtrT(&pReqActive->pIoReq, PDRVDISKAIOREQ);
714
715 if ( pIoReq
716 && (tsCurr > pReqActive->tsStart)
717 && (tsCurr - pReqActive->tsStart) >= pThis->uExpireIntervalMs)
718 {
719 RTMsgError("Request %#p expired (active for %llu ms already)\n",
720 pIoReq, tsCurr - pReqActive->tsStart);
721 RTAssertDebugBreak();
722 }
723 }
724 }
725
726 return VINF_SUCCESS;
727}
728
729/**
730 * Verify a completed read after write request.
731 *
732 * @returns VBox status code.
733 * @param pThis The driver instance data.
734 * @param pIoReq The request to be verified.
735 */
736static int drvdiskintReadAfterWriteVerify(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
737{
738 int rc = VINF_SUCCESS;
739
740 if (pThis->fCheckConsistency)
741 rc = drvdiskintReadVerify(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
742 else /** @todo Implement read after write verification without a memory based image of the disk. */
743 AssertMsgFailed(("TODO\n"));
744
745 return rc;
746}
747
748/* -=-=-=-=- IMedia -=-=-=-=- */
749
750/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIA. */
751#define PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMedia)) )
752/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIAASYNC. */
753#define PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsync)) )
754
755
756/*********************************************************************************************************************************
757* Media interface methods *
758*********************************************************************************************************************************/
759
760/** @interface_method_impl{PDMIMEDIA,pfnRead} */
761static DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
762 uint64_t off, void *pvBuf, size_t cbRead)
763{
764 int rc = VINF_SUCCESS;
765 VDIOLOGENT hIoLogEntry;
766 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
767
768 if (pThis->hIoLogger)
769 {
770 rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_READ, off,
771 cbRead, NULL, &hIoLogEntry);
772 AssertRC(rc);
773 }
774
775 rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
776
777 if (pThis->hIoLogger)
778 {
779 RTSGSEG Seg;
780 RTSGBUF SgBuf;
781
782 Seg.pvSeg = pvBuf;
783 Seg.cbSeg = cbRead;
784 RTSgBufInit(&SgBuf, &Seg, 1);
785
786 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, &SgBuf);
787 AssertRC(rc2);
788 }
789
790 if (RT_FAILURE(rc))
791 return rc;
792
793 if (pThis->fCheckConsistency)
794 {
795 /* Verify the read. */
796 RTSGSEG Seg;
797 Seg.cbSeg = cbRead;
798 Seg.pvSeg = pvBuf;
799 rc = drvdiskintReadVerify(pThis, &Seg, 1, off, cbRead);
800 }
801
802 return rc;
803}
804
805/** @interface_method_impl{PDMIMEDIA,pfnWrite} */
806static DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
807 uint64_t off, const void *pvBuf,
808 size_t cbWrite)
809{
810 int rc = VINF_SUCCESS;
811 VDIOLOGENT hIoLogEntry;
812 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
813
814 if (pThis->hIoLogger)
815 {
816 RTSGSEG Seg;
817 RTSGBUF SgBuf;
818
819 Seg.pvSeg = (void *)pvBuf;
820 Seg.cbSeg = cbWrite;
821 RTSgBufInit(&SgBuf, &Seg, 1);
822
823 rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_WRITE, off,
824 cbWrite, &SgBuf, &hIoLogEntry);
825 AssertRC(rc);
826 }
827
828 if (pThis->fRecordWriteBeforeCompletion)
829 {
830 RTSGSEG Seg;
831 Seg.cbSeg = cbWrite;
832 Seg.pvSeg = (void *)pvBuf;
833
834 rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
835 if (RT_FAILURE(rc))
836 return rc;
837 }
838
839 rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
840
841 if (pThis->hIoLogger)
842 {
843 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, NULL);
844 AssertRC(rc2);
845 }
846
847 if (RT_FAILURE(rc))
848 return rc;
849
850 if ( pThis->fCheckConsistency
851 && !pThis->fRecordWriteBeforeCompletion)
852 {
853 /* Record the write. */
854 RTSGSEG Seg;
855 Seg.cbSeg = cbWrite;
856 Seg.pvSeg = (void *)pvBuf;
857 rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
858 }
859
860 return rc;
861}
862
863static DECLCALLBACK(int) drvdiskintStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
864 PCRTSGSEG paSeg, unsigned cSeg,
865 size_t cbRead, void *pvUser)
866{
867 LogFlow(("%s: uOffset=%llu paSeg=%#p cSeg=%u cbRead=%d pvUser=%#p\n", __FUNCTION__,
868 uOffset, paSeg, cSeg, cbRead, pvUser));
869 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
870 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_READ, uOffset, paSeg, cSeg, cbRead, pvUser);
871 AssertPtr(pIoReq);
872
873 if (pThis->fTraceRequests)
874 drvdiskintIoReqAdd(pThis, pIoReq);
875
876 if (pThis->hIoLogger)
877 {
878 int rc2 = VDDbgIoLogStart(pThis->hIoLogger, true, VDDBGIOLOGREQ_READ, uOffset,
879 cbRead, NULL, &pIoReq->hIoLogEntry);
880 AssertRC(rc2);
881 }
882
883 int rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
884 cbRead, pIoReq);
885 if (rc == VINF_VD_ASYNC_IO_FINISHED)
886 {
887 /* Verify the read now. */
888 if (pThis->fCheckConsistency)
889 {
890 int rc2 = drvdiskintReadVerify(pThis, paSeg, cSeg, uOffset, cbRead);
891 AssertRC(rc2);
892 }
893
894 if (pThis->hIoLogger)
895 {
896 RTSGBUF SgBuf;
897
898 RTSgBufInit(&SgBuf, paSeg, cSeg);
899
900 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, &SgBuf);
901 AssertRC(rc2);
902 }
903
904 if (pThis->fTraceRequests)
905 drvdiskintIoReqRemove(pThis, pIoReq);
906 RTMemFree(pIoReq);
907 }
908 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
909 RTMemFree(pIoReq);
910
911 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
912 return rc;
913}
914
915static DECLCALLBACK(int) drvdiskintStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
916 PCRTSGSEG paSeg, unsigned cSeg,
917 size_t cbWrite, void *pvUser)
918{
919 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d pvUser=%#p\n", __FUNCTION__,
920 uOffset, paSeg, cSeg, cbWrite, pvUser));
921 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
922 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_WRITE, uOffset, paSeg, cSeg, cbWrite, pvUser);
923 AssertPtr(pIoReq);
924
925 if (pThis->fTraceRequests)
926 drvdiskintIoReqAdd(pThis, pIoReq);
927
928 if (pThis->hIoLogger)
929 {
930 RTSGBUF SgBuf;
931
932 RTSgBufInit(&SgBuf, paSeg, cSeg);
933
934 int rc2 = VDDbgIoLogStart(pThis->hIoLogger, true, VDDBGIOLOGREQ_WRITE, uOffset,
935 cbWrite, &SgBuf, &pIoReq->hIoLogEntry);
936 AssertRC(rc2);
937 }
938
939 if (pThis->fRecordWriteBeforeCompletion)
940 {
941 int rc2 = drvdiskintWriteRecord(pThis, paSeg, cSeg, uOffset, cbWrite);
942 AssertRC(rc2);
943 }
944
945 int rc = pThis->pDrvMediaAsync->pfnStartWrite(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
946 cbWrite, pIoReq);
947 if (rc == VINF_VD_ASYNC_IO_FINISHED)
948 {
949 /* Record the write. */
950 if ( pThis->fCheckConsistency
951 && !pThis->fRecordWriteBeforeCompletion)
952 {
953 int rc2 = drvdiskintWriteRecord(pThis, paSeg, cSeg, uOffset, cbWrite);
954 AssertRC(rc2);
955 }
956
957 if (pThis->hIoLogger)
958 {
959 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, NULL);
960 AssertRC(rc2);
961 }
962
963 if (pThis->fTraceRequests)
964 drvdiskintIoReqRemove(pThis, pIoReq);
965
966 RTMemFree(pIoReq);
967 }
968 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
969 RTMemFree(pIoReq);
970
971 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
972 return rc;
973}
974
975/** @interface_method_impl{PDMIMEDIAASYNC,pfnStartFlush} */
976static DECLCALLBACK(int) drvdiskintStartFlush(PPDMIMEDIAASYNC pInterface, void *pvUser)
977{
978 int rc = VINF_SUCCESS;
979 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
980 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_FLUSH, 0, NULL, 0, 0, pvUser);
981 AssertPtr(pIoReq);
982
983 if (pThis->fTraceRequests)
984 drvdiskintIoReqAdd(pThis, pIoReq);
985
986 if (pThis->hIoLogger)
987 {
988 rc = VDDbgIoLogStart(pThis->hIoLogger, true, VDDBGIOLOGREQ_FLUSH, 0,
989 0, NULL, &pIoReq->hIoLogEntry);
990 AssertRC(rc);
991 }
992
993 rc = pThis->pDrvMediaAsync->pfnStartFlush(pThis->pDrvMediaAsync, pIoReq);
994
995 if (rc == VINF_VD_ASYNC_IO_FINISHED)
996 {
997 if (pThis->hIoLogger)
998 {
999 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, NULL);
1000 AssertRC(rc2);
1001 }
1002
1003 RTMemFree(pIoReq);
1004 }
1005 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
1006 RTMemFree(pIoReq);
1007
1008 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1009 return rc;
1010}
1011
1012/** @interface_method_impl{PDMIMEDIAASYNC,pfnStartDiscard} */
1013static DECLCALLBACK(int) drvdiskintStartDiscard(PPDMIMEDIAASYNC pInterface, PCRTRANGE paRanges, unsigned cRanges, void *pvUser)
1014{
1015 int rc = VINF_SUCCESS;
1016 VDIOLOGENT hIoLogEntry;
1017 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1018 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_DISCARD, 0, NULL, 0, 0, pvUser);
1019 AssertPtr(pIoReq);
1020
1021 pIoReq->paRanges = paRanges;
1022 pIoReq->cRanges = cRanges;
1023
1024 if (pThis->hIoLogger)
1025 {
1026 rc = VDDbgIoLogStartDiscard(pThis->hIoLogger, true, paRanges, cRanges, &hIoLogEntry);
1027 AssertRC(rc);
1028 }
1029
1030 rc = pThis->pDrvMediaAsync->pfnStartDiscard(pThis->pDrvMediaAsync, paRanges, cRanges, pIoReq);
1031
1032 if (rc == VINF_VD_ASYNC_IO_FINISHED)
1033 {
1034 if (pThis->hIoLogger)
1035 {
1036 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, NULL);
1037 AssertRC(rc2);
1038 }
1039
1040 RTMemFree(pIoReq);
1041 }
1042 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
1043 RTMemFree(pIoReq);
1044
1045 return rc;
1046}
1047
1048/** @interface_method_impl{PDMIMEDIA,pfnFlush} */
1049static DECLCALLBACK(int) drvdiskintFlush(PPDMIMEDIA pInterface)
1050{
1051 int rc = VINF_SUCCESS;
1052 VDIOLOGENT hIoLogEntry;
1053 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1054
1055 if (pThis->hIoLogger)
1056 {
1057 rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_FLUSH, 0,
1058 0, NULL, &hIoLogEntry);
1059 AssertRC(rc);
1060 }
1061
1062 rc = pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
1063
1064 if (pThis->hIoLogger)
1065 {
1066 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, NULL);
1067 AssertRC(rc2);
1068 }
1069
1070 return rc;
1071}
1072
1073/** @interface_method_impl{PDMIMEDIA,pfnGetSize} */
1074static DECLCALLBACK(uint64_t) drvdiskintGetSize(PPDMIMEDIA pInterface)
1075{
1076 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1077 return pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
1078}
1079
1080/** @interface_method_impl{PDMIMEDIA,pfnIsReadOnly} */
1081static DECLCALLBACK(bool) drvdiskintIsReadOnly(PPDMIMEDIA pInterface)
1082{
1083 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1084 return pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
1085}
1086
1087/** @interface_method_impl{PDMIMEDIA,pfnBiosGetPCHSGeometry} */
1088static DECLCALLBACK(int) drvdiskintBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
1089 PPDMMEDIAGEOMETRY pPCHSGeometry)
1090{
1091 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1092 return pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
1093}
1094
1095/** @interface_method_impl{PDMIMEDIA,pfnBiosSetPCHSGeometry} */
1096static DECLCALLBACK(int) drvdiskintBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
1097 PCPDMMEDIAGEOMETRY pPCHSGeometry)
1098{
1099 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1100 return pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
1101}
1102
1103/** @interface_method_impl{PDMIMEDIA,pfnBiosGetLCHSGeometry} */
1104static DECLCALLBACK(int) drvdiskintBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
1105 PPDMMEDIAGEOMETRY pLCHSGeometry)
1106{
1107 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1108 return pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
1109}
1110
1111/** @interface_method_impl{PDMIMEDIA,pfnBiosSetLCHSGeometry} */
1112static DECLCALLBACK(int) drvdiskintBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
1113 PCPDMMEDIAGEOMETRY pLCHSGeometry)
1114{
1115 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1116 return pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
1117}
1118
1119/** @interface_method_impl{PDMIMEDIA,pfnGetUuid} */
1120static DECLCALLBACK(int) drvdiskintGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
1121{
1122 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1123 return pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, pUuid);
1124}
1125
1126/** @interface_method_impl{PDMIMEDIA,pfnGetSectorSize} */
1127static DECLCALLBACK(uint32_t) drvdiskintGetSectorSize(PPDMIMEDIA pInterface)
1128{
1129 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1130 return pThis->pDrvMedia->pfnGetSectorSize(pThis->pDrvMedia);
1131}
1132
1133/** @interface_method_impl{PDMIMEDIA,pfnDiscard} */
1134static DECLCALLBACK(int) drvdiskintDiscard(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges)
1135{
1136 int rc = VINF_SUCCESS;
1137 VDIOLOGENT hIoLogEntry;
1138 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1139
1140 if (pThis->hIoLogger)
1141 {
1142 rc = VDDbgIoLogStartDiscard(pThis->hIoLogger, false, paRanges, cRanges, &hIoLogEntry);
1143 AssertRC(rc);
1144 }
1145
1146 rc = pThis->pDrvMedia->pfnDiscard(pThis->pDrvMedia, paRanges, cRanges);
1147
1148 if (pThis->hIoLogger)
1149 {
1150 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, NULL);
1151 AssertRC(rc2);
1152 }
1153
1154 if (pThis->fCheckConsistency)
1155 rc = drvdiskintDiscardRecords(pThis, paRanges, cRanges);
1156
1157 return rc;
1158}
1159
1160/** @interface_method_impl{PDMIMEDIA,pfnIoBufAlloc} */
1161static DECLCALLBACK(int) drvdiskintIoBufAlloc(PPDMIMEDIA pInterface, size_t cb, void **ppvNew)
1162{
1163 LogFlowFunc(("\n"));
1164 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1165
1166 return pThis->pDrvMedia->pfnIoBufAlloc(pThis->pDrvMedia, cb, ppvNew);
1167}
1168
1169/** @interface_method_impl{PDMIMEDIA,pfnIoBufFree} */
1170static DECLCALLBACK(int) drvdiskintIoBufFree(PPDMIMEDIA pInterface, void *pv, size_t cb)
1171{
1172 LogFlowFunc(("\n"));
1173 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1174
1175 return pThis->pDrvMedia->pfnIoBufFree(pThis->pDrvMedia, pv, cb);
1176}
1177
1178/** @interface_method_impl{PDMIMEDIA,pfnReadPcBios} */
1179static DECLCALLBACK(int) drvdiskintReadPcBios(PPDMIMEDIA pInterface,
1180 uint64_t off, void *pvBuf, size_t cbRead)
1181{
1182 LogFlowFunc(("\n"));
1183 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1184
1185 return pThis->pDrvMedia->pfnReadPcBios(pThis->pDrvMedia, off, pvBuf, cbRead);
1186}
1187
1188/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
1189
1190/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
1191#define PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsyncPort))) )
1192
1193static DECLCALLBACK(int) drvdiskintAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
1194{
1195 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface);
1196 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)pvUser;
1197 int rc = VINF_SUCCESS;
1198
1199 LogFlowFunc(("pIoReq=%#p\n", pIoReq));
1200
1201 /* Remove from the active list. */
1202 if (pThis->fTraceRequests)
1203 drvdiskintIoReqRemove(pThis, pIoReq);
1204
1205 if (RT_SUCCESS(rcReq) && pThis->fCheckConsistency)
1206 {
1207 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1208 rc = drvdiskintReadVerify(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
1209 else if ( pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE
1210 && !pThis->fRecordWriteBeforeCompletion)
1211 rc = drvdiskintWriteRecord(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
1212 else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_DISCARD)
1213 rc = drvdiskintDiscardRecords(pThis, pIoReq->paRanges, pIoReq->cRanges);
1214 else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ_AFTER_WRITE)
1215 rc = drvdiskintReadAfterWriteVerify(pThis, pIoReq);
1216 else
1217 AssertMsg( pIoReq->enmTxDir == DRVDISKAIOTXDIR_FLUSH
1218 || ( pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE
1219 && pThis->fRecordWriteBeforeCompletion), ("Huh?\n"));
1220
1221 AssertRC(rc);
1222 }
1223
1224 if (pThis->hIoLogger)
1225 {
1226 RTSGBUF SgBuf;
1227
1228 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1229 RTSgBufInit(&SgBuf, pIoReq->paSeg, pIoReq->cSeg);
1230
1231 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, rc, &SgBuf);
1232 AssertRC(rc2);
1233 }
1234
1235 if ( pThis->fReadAfterWrite
1236 && pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE)
1237 {
1238 pIoReq->enmTxDir = DRVDISKAIOTXDIR_READ_AFTER_WRITE;
1239
1240 /* Readd because it was rmeoved above. */
1241 if (pThis->fTraceRequests)
1242 drvdiskintIoReqAdd(pThis, pIoReq);
1243
1244 rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, pIoReq->off, pIoReq->paSeg, pIoReq->cSeg,
1245 pIoReq->cbTransfer, pIoReq);
1246 if (rc == VINF_VD_ASYNC_IO_FINISHED)
1247 {
1248 rc = drvdiskintReadAfterWriteVerify(pThis, pIoReq);
1249
1250 if (pThis->fTraceRequests)
1251 drvdiskintIoReqRemove(pThis, pIoReq);
1252 RTMemFree(pIoReq);
1253 }
1254 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
1255 rc = VINF_SUCCESS;
1256 else if (RT_FAILURE(rc))
1257 RTMemFree(pIoReq);
1258 }
1259 else
1260 {
1261 void *pvUserComplete = pIoReq->pvUser;
1262 drvdiskintIoReqFree(pThis, pIoReq);
1263
1264 rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvUserComplete, rcReq);
1265 }
1266
1267 return rc;
1268}
1269
1270/* -=-=-=-=- IMediaPort -=-=-=-=- */
1271
1272/** Makes a PDRVBLOCK out of a PPDMIMEDIAPORT. */
1273#define PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaPort))) )
1274
1275/**
1276 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
1277 */
1278static DECLCALLBACK(int) drvdiskintQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
1279 uint32_t *piInstance, uint32_t *piLUN)
1280{
1281 PDRVDISKINTEGRITY pThis = PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface);
1282
1283 return pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, ppcszController,
1284 piInstance, piLUN);
1285}
1286
1287/* -=-=-=-=- IBase -=-=-=-=- */
1288
1289/**
1290 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1291 */
1292static DECLCALLBACK(void *) drvdiskintQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1293{
1294 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1295 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1296
1297 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1298 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
1299 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->pDrvMediaAsync ? &pThis->IMediaAsync : NULL);
1300 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, &pThis->IMediaAsyncPort);
1301 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->IMediaPort);
1302 return NULL;
1303}
1304
1305
1306/* -=-=-=-=- driver interface -=-=-=-=- */
1307
1308static DECLCALLBACK(int) drvdiskintTreeDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
1309{
1310 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)pNode;
1311
1312 RT_NOREF(pvUser);
1313
1314 RTMemFree(pSeg->pbSeg);
1315 RTMemFree(pSeg);
1316 return VINF_SUCCESS;
1317}
1318
1319/**
1320 * @copydoc FNPDMDRVDESTRUCT
1321 */
1322static DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
1323{
1324 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1325
1326 if (pThis->pTreeSegments)
1327 {
1328 RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
1329 RTMemFree(pThis->pTreeSegments);
1330 }
1331
1332 if (pThis->fTraceRequests)
1333 {
1334 pThis->fRunning = false;
1335 RTSemEventSignal(pThis->SemEvent);
1336 RTSemEventDestroy(pThis->SemEvent);
1337 }
1338
1339 if (pThis->fCheckDoubleCompletion)
1340 {
1341 /* Free all requests */
1342 while (pThis->papIoReq[pThis->iEntry])
1343 {
1344 RTMemFree(pThis->papIoReq[pThis->iEntry]);
1345 pThis->papIoReq[pThis->iEntry] = NULL;
1346 pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
1347 }
1348 }
1349
1350 if (pThis->hIoLogger)
1351 VDDbgIoLogDestroy(pThis->hIoLogger);
1352}
1353
1354/**
1355 * Construct a disk integrity driver instance.
1356 *
1357 * @copydoc FNPDMDRVCONSTRUCT
1358 */
1359static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1360{
1361 int rc = VINF_SUCCESS;
1362 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1363 LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
1364 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1365
1366 /*
1367 * Validate configuration.
1368 */
1369 if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
1370 "TraceRequests\0"
1371 "CheckIntervalMs\0"
1372 "ExpireIntervalMs\0"
1373 "CheckDoubleCompletions\0"
1374 "HistorySize\0"
1375 "IoLog\0"
1376 "PrepopulateRamDisk\0"
1377 "ReadAfterWrite\0"
1378 "RecordWriteBeforeCompletion\0"))
1379 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1380
1381 rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
1382 AssertRC(rc);
1383 rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
1384 AssertRC(rc);
1385 rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
1386 AssertRC(rc);
1387 rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
1388 AssertRC(rc);
1389 rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
1390 AssertRC(rc);
1391 rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
1392 AssertRC(rc);
1393 rc = CFGMR3QueryBoolDef(pCfg, "PrepopulateRamDisk", &pThis->fPrepopulateRamDisk, false);
1394 AssertRC(rc);
1395 rc = CFGMR3QueryBoolDef(pCfg, "ReadAfterWrite", &pThis->fReadAfterWrite, false);
1396 AssertRC(rc);
1397 rc = CFGMR3QueryBoolDef(pCfg, "RecordWriteBeforeCompletion", &pThis->fRecordWriteBeforeCompletion, false);
1398 AssertRC(rc);
1399
1400 char *pszIoLogFilename = NULL;
1401 rc = CFGMR3QueryStringAlloc(pCfg, "IoLog", &pszIoLogFilename);
1402 Assert(RT_SUCCESS(rc) || rc == VERR_CFGM_VALUE_NOT_FOUND);
1403
1404 /*
1405 * Initialize most of the data members.
1406 */
1407 pThis->pDrvIns = pDrvIns;
1408
1409 /* IBase. */
1410 pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
1411
1412 /* IMedia */
1413 pThis->IMedia.pfnRead = drvdiskintRead;
1414 pThis->IMedia.pfnWrite = drvdiskintWrite;
1415 pThis->IMedia.pfnFlush = drvdiskintFlush;
1416 pThis->IMedia.pfnGetSize = drvdiskintGetSize;
1417 pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
1418 pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
1419 pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
1420 pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
1421 pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
1422 pThis->IMedia.pfnGetUuid = drvdiskintGetUuid;
1423 pThis->IMedia.pfnGetSectorSize = drvdiskintGetSectorSize;
1424 pThis->IMedia.pfnIoBufAlloc = drvdiskintIoBufAlloc;
1425 pThis->IMedia.pfnIoBufFree = drvdiskintIoBufFree;
1426 pThis->IMedia.pfnReadPcBios = drvdiskintReadPcBios;
1427
1428 /* IMediaAsync */
1429 pThis->IMediaAsync.pfnStartRead = drvdiskintStartRead;
1430 pThis->IMediaAsync.pfnStartWrite = drvdiskintStartWrite;
1431 pThis->IMediaAsync.pfnStartFlush = drvdiskintStartFlush;
1432
1433 /* IMediaAsyncPort. */
1434 pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvdiskintAsyncTransferCompleteNotify;
1435
1436 /* IMediaPort. */
1437 pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation;
1438
1439 /* Query the media port interface above us. */
1440 pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
1441 if (!pThis->pDrvMediaPort)
1442 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1443 N_("No media port inrerface above"));
1444
1445 /* Try to attach async media port interface above.*/
1446 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1447
1448 /*
1449 * Try attach driver below and query it's media interface.
1450 */
1451 PPDMIBASE pBase;
1452 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
1453 if (RT_FAILURE(rc))
1454 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1455 N_("Failed to attach driver below us! %Rrc"), rc);
1456
1457 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
1458 if (!pThis->pDrvMedia)
1459 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1460 N_("No media or async media interface below"));
1461
1462 pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
1463
1464 if (pThis->pDrvMedia->pfnDiscard)
1465 pThis->IMedia.pfnDiscard = drvdiskintDiscard;
1466 if ( pThis->pDrvMediaAsync
1467 && pThis->pDrvMediaAsync->pfnStartDiscard)
1468 pThis->IMediaAsync.pfnStartDiscard = drvdiskintStartDiscard;
1469
1470 if (pThis->fCheckConsistency)
1471 {
1472 /* Create the AVL tree. */
1473 pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
1474 if (!pThis->pTreeSegments)
1475 rc = VERR_NO_MEMORY;
1476 }
1477
1478 if (pThis->fTraceRequests)
1479 {
1480 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
1481 {
1482 pThis->apReqActive[i].pIoReq = NULL;
1483 pThis->apReqActive[i].tsStart = 0;
1484 }
1485
1486 pThis->iNextFreeSlot = 0;
1487
1488 /* Init event semaphore. */
1489 rc = RTSemEventCreate(&pThis->SemEvent);
1490 AssertRC(rc);
1491 pThis->fRunning = true;
1492 rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
1493 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
1494 AssertRC(rc);
1495 }
1496
1497 if (pThis->fCheckDoubleCompletion)
1498 {
1499 pThis->iEntry = 0;
1500 pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
1501 AssertPtr(pThis->papIoReq);
1502 }
1503
1504 if (pszIoLogFilename)
1505 {
1506 rc = VDDbgIoLogCreate(&pThis->hIoLogger, pszIoLogFilename, VDDBG_IOLOG_LOG_DATA);
1507 MMR3HeapFree(pszIoLogFilename);
1508 }
1509
1510 /* Read in all data before the start if requested. */
1511 if (pThis->fPrepopulateRamDisk)
1512 {
1513 uint64_t cbDisk = 0;
1514
1515 LogRel(("DiskIntegrity: Prepopulating RAM disk, this will take some time...\n"));
1516
1517 cbDisk = pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
1518 if (cbDisk)
1519 {
1520 uint64_t off = 0;
1521 uint8_t abBuffer[_64K];
1522 RTSGSEG Seg;
1523
1524 Seg.pvSeg = abBuffer;
1525
1526 while (cbDisk)
1527 {
1528 size_t cbThisRead = RT_MIN(cbDisk, sizeof(abBuffer));
1529
1530 rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, abBuffer, cbThisRead);
1531 if (RT_FAILURE(rc))
1532 break;
1533
1534 if (ASMBitFirstSet(abBuffer, sizeof(abBuffer) * 8) != -1)
1535 {
1536 Seg.cbSeg = cbThisRead;
1537 rc = drvdiskintWriteRecord(pThis, &Seg, 1,
1538 off, cbThisRead);
1539 if (RT_FAILURE(rc))
1540 break;
1541 }
1542
1543 cbDisk -= cbThisRead;
1544 off += cbThisRead;
1545 }
1546
1547 LogRel(("DiskIntegrity: Prepopulating RAM disk finished with %Rrc\n", rc));
1548 }
1549 else
1550 return PDMDRV_SET_ERROR(pDrvIns, VERR_INTERNAL_ERROR,
1551 N_("DiskIntegrity: Error querying the media size below"));
1552 }
1553
1554 return rc;
1555}
1556
1557
1558/**
1559 * Block driver registration record.
1560 */
1561const PDMDRVREG g_DrvDiskIntegrity =
1562{
1563 /* u32Version */
1564 PDM_DRVREG_VERSION,
1565 /* szName */
1566 "DiskIntegrity",
1567 /* szRCMod */
1568 "",
1569 /* szR0Mod */
1570 "",
1571 /* pszDescription */
1572 "Disk integrity driver.",
1573 /* fFlags */
1574 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1575 /* fClass. */
1576 PDM_DRVREG_CLASS_BLOCK,
1577 /* cMaxInstances */
1578 ~0U,
1579 /* cbInstance */
1580 sizeof(DRVDISKINTEGRITY),
1581 /* pfnConstruct */
1582 drvdiskintConstruct,
1583 /* pfnDestruct */
1584 drvdiskintDestruct,
1585 /* pfnRelocate */
1586 NULL,
1587 /* pfnIOCtl */
1588 NULL,
1589 /* pfnPowerOn */
1590 NULL,
1591 /* pfnReset */
1592 NULL,
1593 /* pfnSuspend */
1594 NULL,
1595 /* pfnResume */
1596 NULL,
1597 /* pfnAttach */
1598 NULL,
1599 /* pfnDetach */
1600 NULL,
1601 /* pfnPowerOff */
1602 NULL,
1603 /* pfnSoftReset */
1604 NULL,
1605 /* u32EndVersion */
1606 PDM_DRVREG_VERSION
1607};
1608
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette