1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*
7         Module name:
8 
9    remap.cpp
10 
11         Abstract:
12 
13    This file contains filesystem-specific routines
14    responsible for disk space management
15 
16 */
17 
18 #include "udf.h"
19 
20 #define         UDF_BUG_CHECK_ID                UDF_FILE_UDF_INFO_REMAP
21 
22 typedef struct _UDF_VERIFY_ITEM {
23     lba_t      lba;
24     ULONG      crc;
25     PUCHAR     Buffer;
26     LIST_ENTRY vrfList;
27     BOOLEAN    queued;
28 } UDF_VERIFY_ITEM, *PUDF_VERIFY_ITEM;
29 
30 typedef struct _UDF_VERIFY_REQ_RANGE {
31     lba_t      lba;
32     uint32     BCount;
33 } UDF_VERIFY_REQ_RANGE, *PUDF_VERIFY_REQ_RANGE;
34 
35 #define MAX_VREQ_RANGES  128
36 
37 typedef struct _UDF_VERIFY_REQ {
38     PVCB       Vcb;
39     PUCHAR     Buffer;
40     ULONG      nReq;
41     UDF_VERIFY_REQ_RANGE vr[MAX_VREQ_RANGES];
42 #ifndef _CONSOLE
43     WORK_QUEUE_ITEM VerifyItem;
44 #endif
45 } UDF_VERIFY_REQ, *PUDF_VERIFY_REQ;
46 
47 VOID
48 UDFVRemoveBlock(
49     PUDF_VERIFY_CTX VerifyCtx,
50     PUDF_VERIFY_ITEM vItem
51     );
52 
53 OSSTATUS
54 UDFVInit(
55     IN PVCB Vcb
56     )
57 {
58     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
59     uint32 i;
60     OSSTATUS status = STATUS_SUCCESS;
61     BOOLEAN res_inited = FALSE;
62 
63     if(VerifyCtx->VInited) {
64         UDFPrint(("Already inited\n"));
65         return STATUS_SUCCESS;
66     }
67 
68     _SEH2_TRY {
69         RtlZeroMemory(VerifyCtx, sizeof(UDF_VERIFY_CTX));
70         if(!Vcb->VerifyOnWrite) {
71             UDFPrint(("Verify is disabled\n"));
72             return STATUS_SUCCESS;
73         }
74         if(Vcb->CDR_Mode) {
75             UDFPrint(("Verify is not intended for CD/DVD-R\n"));
76             return STATUS_SUCCESS;
77         }
78         if(!OS_SUCCESS(status = ExInitializeResourceLite(&(VerifyCtx->VerifyLock)))) {
79             try_return(status);
80         }
81         res_inited = TRUE;
82         VerifyCtx->ItemCount = 0;
83         VerifyCtx->StoredBitMap = (uint8*)DbgAllocatePoolWithTag(PagedPool, (i = (Vcb->LastPossibleLBA+1+7)>>3), 'mNWD' );
84         if(VerifyCtx->StoredBitMap) {
85             RtlZeroMemory(VerifyCtx->StoredBitMap, i);
86         } else {
87             UDFPrint(("Can't alloc verify bitmap for %x blocks\n", Vcb->LastPossibleLBA));
88             try_return(status = STATUS_INSUFFICIENT_RESOURCES);
89         }
90         InitializeListHead(&(VerifyCtx->vrfList));
91         KeInitializeEvent(&(VerifyCtx->vrfEvent), SynchronizationEvent, FALSE);
92         VerifyCtx->WaiterCount = 0;
93         VerifyCtx->VInited = TRUE;
94 
95 try_exit: NOTHING;
96 
97     } _SEH2_FINALLY {
98 
99         if(!OS_SUCCESS(status)) {
100             if(res_inited) {
101                 ExDeleteResourceLite(&(VerifyCtx->VerifyLock));
102             }
103         }
104     } _SEH2_END;
105     return status;
106 } // end UDFVInit()
107 
108 VOID
109 UDFVWaitQueued(
110     PUDF_VERIFY_CTX VerifyCtx
111     )
112 {
113     ULONG w;
114 
115     while(VerifyCtx->QueuedCount) {
116         UDFPrint(("UDFVWaitQueued: wait for completion (%d)\n", VerifyCtx->QueuedCount));
117         w = InterlockedIncrement((PLONG)&(VerifyCtx->WaiterCount));
118         UDFPrint(("  %d waiters\n", w));
119         DbgWaitForSingleObject(&(VerifyCtx->vrfEvent), NULL);
120         if((w = InterlockedDecrement((PLONG)&(VerifyCtx->WaiterCount)))) {
121             UDFPrint(("  still %d waiters, q %d\n", w, VerifyCtx->QueuedCount));
122             if(!VerifyCtx->QueuedCount) {
123                 UDFPrint(("  pulse event\n", w));
124                 KeSetEvent(&(VerifyCtx->vrfEvent), 0, FALSE);
125             }
126         }
127     }
128     return;
129 } // end UDFVWaitQueued()
130 
131 VOID
132 UDFVRelease(
133     IN PVCB Vcb
134     )
135 {
136     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
137     PLIST_ENTRY Link;
138     PUDF_VERIFY_ITEM vItem;
139 
140     if(!VerifyCtx->VInited) {
141         return;
142     }
143 
144     UDFPrint(("UDFVRelease: wait for completion\n"));
145     UDFVWaitQueued(VerifyCtx);
146 
147     UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
148 
149     Link = VerifyCtx->vrfList.Flink;
150 
151     while(Link != &(VerifyCtx->vrfList)) {
152         vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
153         Link = Link->Flink;
154         //DbgFreePool(vItem);
155         UDFVRemoveBlock(VerifyCtx, vItem);
156     }
157     VerifyCtx->VInited = FALSE;
158 
159     UDFReleaseResource(&(VerifyCtx->VerifyLock));
160 
161     ExDeleteResourceLite(&(VerifyCtx->VerifyLock));
162     DbgFreePool(VerifyCtx->StoredBitMap);
163 
164     RtlZeroMemory(VerifyCtx, sizeof(UDF_VERIFY_CTX));
165 
166     return;
167 } // end UDFVRelease()
168 
169 PUDF_VERIFY_ITEM
170 UDFVStoreBlock(
171     IN PVCB Vcb,
172     IN uint32 LBA,
173     IN PVOID Buffer,
174     PLIST_ENTRY Link
175     )
176 {
177     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
178     PUDF_VERIFY_ITEM vItem;
179 
180     UDFPrint(("v-add %x\n", LBA));
181 
182     vItem = (PUDF_VERIFY_ITEM)DbgAllocatePoolWithTag(PagedPool, sizeof(UDF_VERIFY_ITEM)+Vcb->BlockSize, 'bvWD');
183     if(!vItem)
184         return NULL;
185     RtlCopyMemory(vItem+1, Buffer, Vcb->BlockSize);
186     vItem->lba = LBA;
187     vItem->crc = crc32((PUCHAR)Buffer, Vcb->BlockSize);
188     vItem->Buffer = (PUCHAR)(vItem+1);
189     vItem->queued = FALSE;
190     InitializeListHead(&(vItem->vrfList));
191     InsertTailList(Link, &(vItem->vrfList));
192     UDFSetBit(VerifyCtx->StoredBitMap, LBA);
193     VerifyCtx->ItemCount++;
194     return vItem;
195 } // end UDFVStoreBlock()
196 
197 VOID
198 UDFVUpdateBlock(
199     IN PVCB Vcb,
200     IN PVOID Buffer,
201     PUDF_VERIFY_ITEM vItem
202     )
203 {
204     UDFPrint(("v-upd %x\n", vItem->lba));
205     RtlCopyMemory(vItem+1, Buffer, Vcb->BlockSize);
206     vItem->crc = crc32((PUCHAR)Buffer, Vcb->BlockSize);
207     return;
208 } // end UDFVUpdateBlock()
209 
210 VOID
211 UDFVRemoveBlock(
212     PUDF_VERIFY_CTX VerifyCtx,
213     PUDF_VERIFY_ITEM vItem
214     )
215 {
216     UDFPrint(("v-del %x\n", vItem->lba));
217     UDFClrBit(VerifyCtx->StoredBitMap, vItem->lba);
218     RemoveEntryList(&(vItem->vrfList));
219     VerifyCtx->ItemCount--;
220     DbgFreePool(vItem);
221     return;
222 } // end UDFVUpdateBlock()
223 
224 OSSTATUS
225 UDFVWrite(
226     IN PVCB Vcb,
227     IN void* Buffer,     // Target buffer
228     IN uint32 BCount,
229     IN uint32 LBA,
230 //    OUT PSIZE_T WrittenBytes,
231     IN uint32 Flags
232     )
233 {
234     PLIST_ENTRY Link;
235     PUDF_VERIFY_ITEM vItem;
236     //PUDF_VERIFY_ITEM vItem1;
237     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
238     ULONG i;
239     ULONG n;
240     //uint32 prev_lba;
241 
242     if(!VerifyCtx->VInited) {
243         return STATUS_SUCCESS;
244     }
245 
246     UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
247 
248     for(i=0, n=0; i<BCount; i++) {
249         if(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i)) {
250             // some blocks are remembered
251             n++;
252         }
253     }
254 
255     if(n == BCount) {
256         // update all blocks
257         n = 0;
258         Link = VerifyCtx->vrfList.Blink;
259         while(Link != &(VerifyCtx->vrfList)) {
260             vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
261             Link = Link->Blink;
262             if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
263                 ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, vItem->lba));
264                 UDFVUpdateBlock(Vcb, ((PUCHAR)Buffer)+(vItem->lba-LBA)*Vcb->BlockSize, vItem);
265                 n++;
266                 if(n == BCount) {
267                     // all updated
268                     break;
269                 }
270             }
271         }
272     } else
273     if(n) {
274 #if 0
275         // find remembered blocks (the 1st one)
276         Link = VerifyCtx->vrfList.Blink;
277         while(Link != &(VerifyCtx->vrfList)) {
278             vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
279             Link = Link->Blink;
280             if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
281                 //UDFVRemoveBlock(VerifyCtx, vItem);
282                 break;
283             }
284         }
285 
286         // check if contiguous
287         i=1;
288         prev_lba = vItem->lba;
289         vItem1 = vItem;
290         Link = Link->Blink;
291         while((i < n) && (Link != &(VerifyCtx->vrfList))) {
292             vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
293             Link = Link->Blink;
294             if(vItem->lba > LBA || vItem->lba >= LBA+BCount) {
295                 // end
296                 break;
297             }
298             if(vItem->lba < prev_lba) {
299                 // not sorted
300                 break;
301             }
302             prev_lba = vItem->lba;
303             i++;
304         }
305 
306         if(i == n) {
307             // cont
308         } else {
309             // drop all and add again
310         }
311 
312         vItem1 = vItem;
313         for(i=0; i<BCount; i++) {
314             if(vItem->lba == LBA+i) {
315                 ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i));
316                 UDFVUpdateBlock(Vcb, ((PUCHAR)Buffer)+i*Vcb->BlockSize, vItem);
317                 continue;
318             }
319             if(vItem1->lba == LBA+i) {
320                 ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i));
321                 UDFVUpdateBlock(Vcb, ((PUCHAR)Buffer)+i*Vcb->BlockSize, vItem1);
322                 continue;
323             }
324             if(vItem1->lba > LBA+i) {
325                 // just insert this block
326                 ASSERT(!UDFGetBit(VerifyCtx->StoredBitMap, LBA+i));
327                 UDFVStoreBlock(Vcb, LBA+i, ((PUCHAR)Buffer)+i*Vcb->BlockSize, &(vItem1->vrfList));
328             } else {
329                 vItem = CONTAINING_RECORD( vItem->vrfList.Blink, UDF_VERIFY_ITEM, vrfList );
330             }
331         }
332 #else
333         Link = VerifyCtx->vrfList.Blink;
334         i=0;
335         while(Link != &(VerifyCtx->vrfList)) {
336             vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
337             Link = Link->Blink;
338             if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
339                 UDFVRemoveBlock(VerifyCtx, vItem);
340                 i++;
341                 if(i == n) {
342                     // all killed
343                     break;
344                 }
345             }
346         }
347         goto remember_all;
348 #endif
349 
350     } else {
351 remember_all:
352         // remember all blocks
353         for(i=0; i<BCount; i++) {
354             ASSERT(!UDFGetBit(VerifyCtx->StoredBitMap, LBA+i));
355             UDFVStoreBlock(Vcb, LBA+i, ((PUCHAR)Buffer)+i*Vcb->BlockSize, &(VerifyCtx->vrfList));
356         }
357     }
358 
359     if(VerifyCtx->ItemCount > UDF_MAX_VERIFY_CACHE) {
360         UDFVVerify(Vcb, UFD_VERIFY_FLAG_LOCKED);
361     }
362 
363     UDFReleaseResource(&(VerifyCtx->VerifyLock));
364 
365     if(VerifyCtx->ItemCount > UDF_MAX_VERIFY_CACHE*2) {
366         //UDFVVerify(Vcb, UFD_VERIFY_FLAG_LOCKED);
367         // TODO: make some delay
368     }
369 
370     return STATUS_SUCCESS;
371 
372 } // end UDFVWrite()
373 
374 OSSTATUS
375 UDFVRead(
376     IN PVCB Vcb,
377     IN void* Buffer,     // Target buffer
378     IN uint32 BCount,
379     IN uint32 LBA,
380 //    OUT uint32* ReadBytes,
381     IN uint32 Flags
382     )
383 {
384     PLIST_ENTRY Link;
385     PUDF_VERIFY_ITEM vItem;
386     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
387     ULONG crc;
388     ULONG i;
389     ULONG n;
390     OSSTATUS status = STATUS_SUCCESS;
391     uint32* bm;
392 
393     if(!VerifyCtx->VInited) {
394         return STATUS_SUCCESS;
395         //return STATUS_UNSUCCESSFUL;
396     }
397 
398     UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
399 
400     for(i=0, n=0; i<BCount; i++) {
401         if(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i)) {
402             // some blocks are remembered
403             n++;
404         }
405     }
406 
407     if(!n) {
408         // no blocks are remembered
409         UDFReleaseResource(&(VerifyCtx->VerifyLock));
410         return STATUS_SUCCESS;
411     }
412 
413     Link = VerifyCtx->vrfList.Flink;
414     i=0;
415     while(Link != &(VerifyCtx->vrfList)) {
416         vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
417         Link = Link->Flink;
418         if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
419             ASSERT(UDFGetBit(VerifyCtx->StoredBitMap, vItem->lba));
420             i++;
421             if(!(Flags & PH_READ_VERIFY_CACHE)) {
422                 crc = crc32((PUCHAR)Buffer+(vItem->lba - LBA)*Vcb->BlockSize, Vcb->BlockSize);
423                 if(vItem->crc != crc) {
424                     UDFPrint(("UDFVRead: stored %x != %x\n", vItem->crc, crc));
425                     RtlCopyMemory((PUCHAR)Buffer+(vItem->lba - LBA)*Vcb->BlockSize, vItem->Buffer, Vcb->BlockSize);
426                     status = STATUS_FT_WRITE_RECOVERY;
427 
428                     if(!(bm = (uint32*)(Vcb->BSBM_Bitmap))) {
429                         crc = (Vcb->LastPossibleLBA+1+7) >> 3; // reuse 'crc' variable
430                         bm = (uint32*)(Vcb->BSBM_Bitmap = (int8*)DbgAllocatePoolWithTag(NonPagedPool, crc, 'mNWD' ));
431                         if(bm) {
432                             RtlZeroMemory(bm, crc);
433                         } else {
434                             UDFPrint(("Can't alloc BSBM for %x blocks\n", Vcb->LastPossibleLBA));
435                         }
436                     }
437                     if(bm) {
438                         UDFSetBit(bm, vItem->lba);
439                         UDFPrint(("Set BB @ %#x\n", vItem->lba));
440                     }
441 #ifdef _BROWSE_UDF_
442                     bm = (uint32*)(Vcb->FSBM_Bitmap);
443                     if(bm) {
444                         UDFSetUsedBit(bm, vItem->lba);
445                         UDFPrint(("Set BB @ %#x as used\n", vItem->lba));
446                     }
447 #endif //_BROWSE_UDF_
448                 } else {
449                     // ok
450                 }
451             } else {
452                 UDFPrint(("UDFVRead: get cached @ %x\n", vItem->lba));
453                 RtlCopyMemory((PUCHAR)Buffer+(vItem->lba - LBA)*Vcb->BlockSize, vItem->Buffer, Vcb->BlockSize);
454             }
455             if(i >= n) {
456                 // no more blocks expected
457                 break;
458             }
459         }
460     }
461 
462     if((status == STATUS_SUCCESS && !(Flags & PH_KEEP_VERIFY_CACHE)) || (Flags & PH_FORGET_VERIFIED)) {
463         // ok, forget this, no errors found
464         Link = VerifyCtx->vrfList.Flink;
465         i = 0;
466         while(Link != &(VerifyCtx->vrfList)) {
467             vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
468             Link = Link->Flink;
469             if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
470                 i++;
471                 UDFVRemoveBlock(VerifyCtx, vItem);
472                 if(i >= n) {
473                     // no more blocks expected
474                     break;
475                 }
476             }
477         }
478     }
479 
480     UDFReleaseResource(&(VerifyCtx->VerifyLock));
481     return status;
482 
483 } // end UDFVRead()
484 
485 OSSTATUS
486 UDFVForget(
487     IN PVCB Vcb,
488     IN uint32 BCount,
489     IN uint32 LBA,
490     IN uint32 Flags
491     )
492 {
493     PLIST_ENTRY Link;
494     PUDF_VERIFY_ITEM vItem;
495     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
496     ULONG i;
497     ULONG n;
498     OSSTATUS status = STATUS_SUCCESS;
499 
500     if(!VerifyCtx->VInited) {
501         return STATUS_UNSUCCESSFUL;
502     }
503 
504     UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
505 
506     for(i=0, n=0; i<BCount; i++) {
507         if(UDFGetBit(VerifyCtx->StoredBitMap, LBA+i)) {
508             // some blocks are remembered
509             n++;
510         }
511     }
512 
513     if(!n) {
514         // no blocks are remembered
515         UDFReleaseResource(&(VerifyCtx->VerifyLock));
516         return STATUS_SUCCESS;
517     }
518 
519     Link = VerifyCtx->vrfList.Flink;
520     i = 0;
521     while(Link != &(VerifyCtx->vrfList)) {
522         vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
523         Link = Link->Flink;
524         if(vItem->lba >= LBA && vItem->lba < LBA+BCount) {
525             i++;
526             UDFVRemoveBlock(VerifyCtx, vItem);
527             if(i >= n) {
528                 // no more blocks expected
529                 break;
530             }
531         }
532     }
533 
534     UDFReleaseResource(&(VerifyCtx->VerifyLock));
535     return status;
536 
537 } // end UDFVForget()
538 
539 VOID
540 NTAPI
541 UDFVWorkItem(
542     PVOID Context
543     )
544 {
545     PUDF_VERIFY_REQ VerifyReq = (PUDF_VERIFY_REQ)Context;
546     PVCB Vcb = VerifyReq->Vcb;
547     SIZE_T ReadBytes;
548 //    OSSTATUS RC;
549     ULONG i;
550 
551     ReadBytes = (SIZE_T)Vcb;
552 #if 1
553     if(Vcb->SparingCountFree) {
554         WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE);
555         for(i=0; i<VerifyReq->nReq; i++) {
556             UDFTIOVerify(Vcb,
557                          VerifyReq->Buffer,     // Target buffer
558                          VerifyReq->vr[i].BCount << Vcb->BlockSizeBits,
559                          VerifyReq->vr[i].lba,
560                          &ReadBytes,
561                          PH_TMP_BUFFER | PH_VCB_IN_RETLEN /*| PH_LOCK_CACHE*/);
562         }
563         WCacheEODirect__(&(Vcb->FastCache), Vcb);
564     } else {
565         for(i=0; i<VerifyReq->nReq; i++) {
566             UDFPrint(("!!! No more space for remap !!!\n"));
567             UDFPrint(("  try del from verify cache @ %x\n", VerifyReq->vr[i].lba));
568             UDFVRead(Vcb, VerifyReq->Buffer, VerifyReq->vr[i].BCount, VerifyReq->vr[i].lba,
569                      PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER);
570         }
571     }
572 #else
573     for(i=0; i<VerifyReq->nReq; i++) {
574         if(Vcb->SparingCountFree) {
575             WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE);
576             RC = UDFTIOVerify(Vcb,
577                            VerifyReq->Buffer,     // Target buffer
578                            VerifyReq->vr[i].BCount << Vcb->BlockSizeBits,
579                            VerifyReq->vr[i].lba,
580                            &ReadBytes,
581                            PH_TMP_BUFFER | PH_VCB_IN_RETLEN /*| PH_LOCK_CACHE*/);
582             WCacheEODirect__(&(Vcb->FastCache), Vcb);
583         } else {
584             UDFPrint(("!!! No more space for remap !!!\n"));
585             UDFPrint(("  try del from verify cache @ %x\n", VerifyReq->vr[i].lba));
586             RC = UDFVRead(Vcb, VerifyReq->Buffer, VerifyReq->vr[i].BCount, VerifyReq->vr[i].lba,
587                           PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER);
588         }
589     }
590 #endif
591     DbgFreePool(VerifyReq->Buffer);
592     DbgFreePool(VerifyReq);
593     InterlockedDecrement((PLONG)&(Vcb->VerifyCtx.QueuedCount));
594     UDFPrint(("  QueuedCount = %d\n", Vcb->VerifyCtx.QueuedCount));
595     UDFPrint(("  Setting event...\n"));
596     KeSetEvent(&(Vcb->VerifyCtx.vrfEvent), 0, FALSE);
597     return;
598 } // end UDFVWorkItem()
599 
600 VOID
601 UDFVVerify(
602     IN PVCB Vcb,
603     IN ULONG Flags
604     )
605 {
606     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
607     PLIST_ENTRY Link;
608     PUDF_VERIFY_ITEM vItem;
609     PUDF_VERIFY_REQ VerifyReq = NULL;
610     ULONG len, max_len=0;
611     lba_t prev_lba;
612     //PUCHAR tmp_buff;
613     ULONG i;
614     BOOLEAN do_vrf = FALSE;
615 
616     if(!VerifyCtx->VInited) {
617         return;
618     }
619     if(VerifyCtx->QueuedCount) {
620         if(Flags & UFD_VERIFY_FLAG_WAIT) {
621             UDFPrint(("  wait for verify flush\n"));
622             goto wait;
623         }
624         UDFPrint(("  verify flush already queued\n"));
625         return;
626     }
627 
628     if(!(Flags & (UFD_VERIFY_FLAG_FORCE | UFD_VERIFY_FLAG_BG))) {
629         if(VerifyCtx->ItemCount < UDF_MAX_VERIFY_CACHE) {
630             return;
631         }
632 
633     }
634     if(!(Flags & UFD_VERIFY_FLAG_LOCKED)) {
635         UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
636     }
637 
638     if(Flags & UFD_VERIFY_FLAG_FORCE) {
639         i = VerifyCtx->ItemCount;
640     } else {
641         if(VerifyCtx->ItemCount >= UDF_MAX_VERIFY_CACHE) {
642             i = VerifyCtx->ItemCount - UDF_VERIFY_CACHE_LOW;
643         } else {
644             i = min(UDF_VERIFY_CACHE_GRAN, VerifyCtx->ItemCount);
645         }
646     }
647 
648     Link = VerifyCtx->vrfList.Flink;
649     prev_lba = -2;
650     len = 0;
651 
652     while(i) {
653         ASSERT(Link != &(VerifyCtx->vrfList));
654 /*
655         if(Link == &(VerifyCtx->vrfList)) {
656             if(!len)
657                 break;
658             i=1;
659             goto queue_req;
660         }
661 */
662         vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
663         Link = Link->Flink;
664 
665         //
666         if(!vItem->queued && (prev_lba+len == vItem->lba)) {
667             vItem->queued = TRUE;
668             len++;
669         } else {
670             if(len) {
671                 do_vrf = TRUE;
672             } else {
673                 len = 1;
674                 prev_lba = vItem->lba;
675             }
676         }
677         if((i == 1) && len) {
678             do_vrf = TRUE;
679         }
680         if(len >= 0x100) {
681             do_vrf = TRUE;
682         }
683         if(do_vrf) {
684 //queue_req:
685             if(!VerifyReq) {
686                 VerifyReq = (PUDF_VERIFY_REQ)DbgAllocatePoolWithTag(NonPagedPool, sizeof(UDF_VERIFY_REQ), 'bNWD');
687                 if(VerifyReq) {
688                     RtlZeroMemory(VerifyReq, sizeof(UDF_VERIFY_REQ));
689                     VerifyReq->Vcb    = Vcb;
690                 }
691             }
692             if(VerifyReq) {
693 
694                 VerifyReq->vr[VerifyReq->nReq].lba    = prev_lba;
695                 VerifyReq->vr[VerifyReq->nReq].BCount = len;
696                 VerifyReq->nReq++;
697                 if(max_len < len) {
698                     max_len = len;
699                 }
700 
701                 if((VerifyReq->nReq >= MAX_VREQ_RANGES) || (i == 1)) {
702 
703                     VerifyReq->Buffer = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, max_len * Vcb->BlockSize, 'bNWD');
704                     if(VerifyReq->Buffer) {
705                         InterlockedIncrement((PLONG)&(VerifyCtx->QueuedCount));
706 #ifndef _CONSOLE
707                         ExInitializeWorkItem( &(VerifyReq->VerifyItem),
708                                               UDFVWorkItem,
709                                               VerifyReq );
710                         ExQueueWorkItem( &(VerifyReq->VerifyItem), CriticalWorkQueue );
711 #else
712                         UDFVWorkItem(VerifyReq);
713 #endif
714                     } else {
715                         DbgFreePool(VerifyReq);
716                     }
717                     VerifyReq = NULL;
718                     max_len = 0;
719                 } else {
720                 }
721             }
722             len = 1;
723             prev_lba = vItem->lba;
724             do_vrf = FALSE;
725         }
726         i--;
727     }
728 
729     if(!(Flags & UFD_VERIFY_FLAG_LOCKED)) {
730         UDFReleaseResource(&(VerifyCtx->VerifyLock));
731     }
732     if(Flags & UFD_VERIFY_FLAG_WAIT) {
733 wait:
734         UDFPrint(("UDFVVerify: wait for completion\n"));
735         UDFVWaitQueued(VerifyCtx);
736     }
737 
738     return;
739 } // end UDFVVerify()
740 
741 VOID
742 UDFVFlush(
743     IN PVCB Vcb
744     )
745 {
746     PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
747 
748     if(!VerifyCtx->VInited) {
749         return;
750     }
751 
752     UDFPrint(("UDFVFlush: wait for completion\n"));
753     UDFVWaitQueued(VerifyCtx);
754 
755     UDFVVerify(Vcb, UFD_VERIFY_FLAG_FORCE);
756 
757     UDFPrint(("UDFVFlush: wait for completion (2)\n"));
758     UDFVWaitQueued(VerifyCtx);
759 } // end UDFVFlush()
760 
761 BOOLEAN
762 __fastcall
763 UDFCheckArea(
764     IN PVCB Vcb,
765     IN lba_t LBA,
766     IN uint32 BCount
767     )
768 {
769     uint8* buff;
770     OSSTATUS RC;
771     SIZE_T ReadBytes;
772     uint32 i, d;
773     BOOLEAN ext_ok = TRUE;
774     EXTENT_MAP Map[2];
775     uint32 PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits;
776 
777     buff = (uint8*)DbgAllocatePoolWithTag(NonPagedPool, Vcb->WriteBlockSize, 'bNWD' );
778     if(buff) {
779         for(i=0; i<BCount; i+=d) {
780             if(!((LBA+i) & (PS-1)) &&
781                (i+PS <= BCount)) {
782                 d = PS;
783             } else {
784                 d = 1;
785             }
786             RC = UDFTRead(Vcb,
787                            buff,
788                            d << Vcb->BlockSizeBits,
789                            LBA+i,
790                            &ReadBytes,
791                            PH_TMP_BUFFER);
792 
793             if(RC != STATUS_SUCCESS) {
794                 Map[0].extLocation = LBA+i;
795                 Map[0].extLength = d << Vcb->BlockSizeBits;
796                 UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(Map[0]), AS_DISCARDED | AS_BAD); // free
797                 ext_ok = FALSE;
798             }
799         }
800         DbgFreePool(buff);
801     }
802     return ext_ok;
803 } // end UDFCheckArea()
804 
805 /*
806     This routine remaps sectors from bad packet
807  */
808 OSSTATUS
809 __fastcall
810 UDFRemapPacket(
811     IN PVCB Vcb,
812     IN uint32 Lba,
813     IN BOOLEAN RemapSpared
814     )
815 {
816     uint32 i, max, BS, orig;
817     PSPARING_MAP Map;
818     BOOLEAN verified = FALSE;
819 
820     if(Vcb->SparingTable) {
821 
822         max = Vcb->SparingCount;
823         BS = Vcb->SparingBlockSize;
824 
825         // use sparing table for relocation
826         if(Vcb->SparingCountFree == (ULONG)-1) {
827             UDFPrint(("calculate free spare areas\n"));
828 re_check:
829             UDFPrint(("verify spare area\n"));
830             Vcb->SparingCountFree = 0;
831             Map = Vcb->SparingTable;
832             for(i=0;i<max;i++,Map++) {
833                 if(Map->origLocation == SPARING_LOC_AVAILABLE) {
834                     if(UDFCheckArea(Vcb, Map->mappedLocation, BS)) {
835                         Vcb->SparingCountFree++;
836                     } else {
837                         UDFPrint(("initial check: bad spare block @ %x\n", Map->mappedLocation));
838                         Map->origLocation = SPARING_LOC_CORRUPTED;
839                         Vcb->SparingTableModified = TRUE;
840                     }
841                 }
842             }
843         }
844         if(!Vcb->SparingCountFree) {
845             UDFPrint(("sparing table full\n"));
846             return STATUS_DISK_FULL;
847         }
848 
849         Map = Vcb->SparingTable;
850         Lba &= ~(BS-1);
851         for(i=0;i<max;i++,Map++) {
852             orig = Map->origLocation;
853             if(Lba == (orig & ~(BS-1)) ) {
854                 // already remapped
855 
856                 UDFPrint(("remap remapped: bad spare block @ %x\n", Map->mappedLocation));
857                 if(!verified) {
858                     verified = TRUE;
859                     goto re_check;
860                 }
861 
862                 if(!RemapSpared) {
863                     return STATUS_SHARING_VIOLATION;
864                 } else {
865                     // look for another remap area
866                     Map->origLocation = SPARING_LOC_CORRUPTED;
867                     Vcb->SparingTableModified = TRUE;
868                     Vcb->SparingCountFree--;
869                     break;
870                 }
871             }
872         }
873         Map = Vcb->SparingTable;
874         for(i=0;i<max;i++,Map++) {
875             if(Map->origLocation == SPARING_LOC_AVAILABLE) {
876                 UDFPrint(("remap %x -> %x\n", Lba, Map->mappedLocation));
877                 Map->origLocation = Lba;
878                 Vcb->SparingTableModified = TRUE;
879                 Vcb->SparingCountFree--;
880                 return STATUS_SUCCESS;
881             }
882         }
883         UDFPrint(("sparing table full\n"));
884         return STATUS_DISK_FULL;
885     }
886     return STATUS_UNSUCCESSFUL;
887 } // end UDFRemapPacket()
888 
889 /*
890     This routine releases sector mapping when entire packet is marked as free
891  */
892 OSSTATUS
893 __fastcall
894 UDFUnmapRange(
895     IN PVCB Vcb,
896     IN uint32 Lba,
897     IN uint32 BCount
898     )
899 {
900     uint32 i, max, BS, orig;
901     PSPARING_MAP Map;
902 
903     if(Vcb->SparingTable) {
904         // use sparing table for relocation
905 
906         max = Vcb->SparingCount;
907         BS = Vcb->SparingBlockSize;
908         Map = Vcb->SparingTable;
909         for(i=0;i<max;i++,Map++) {
910             orig = Map->origLocation;
911             switch(orig) {
912             case SPARING_LOC_AVAILABLE:
913             case SPARING_LOC_CORRUPTED:
914                 continue;
915             }
916             if(orig >= Lba &&
917               (orig+BS) <= (Lba+BCount)) {
918                 // unmap
919                 UDFPrint(("unmap %x -> %x\n", orig, Map->mappedLocation));
920                 Map->origLocation = SPARING_LOC_AVAILABLE;
921                 Vcb->SparingTableModified = TRUE;
922                 Vcb->SparingCountFree++;
923             }
924         }
925     }
926     return STATUS_SUCCESS;
927 } // end UDFUnmapRange()
928 
929 /*
930     This routine returns physical address for relocated sector
931  */
932 uint32
933 __fastcall
934 UDFRelocateSector(
935     IN PVCB Vcb,
936     IN uint32 Lba
937     )
938 {
939     uint32 i, max, BS, orig;
940 
941     if(Vcb->SparingTable) {
942         // use sparing table for relocation
943         uint32 _Lba;
944         PSPARING_MAP Map = Vcb->SparingTable;
945 
946         max = Vcb->SparingCount;
947         BS = Vcb->SparingBlockSize;
948         _Lba = Lba & ~(BS-1);
949         for(i=0;i<max;i++,Map++) {
950             orig = Map->origLocation;
951             if(_Lba == (orig & ~(BS-1)) ) {
952             //if( (Lba >= (orig = Map->origLocation)) && (Lba < orig + BS) ) {
953                 return Map->mappedLocation + Lba - orig;
954             }
955         }
956     } else if(Vcb->Vat) {
957         // use VAT for relocation
958         uint32* Map = Vcb->Vat;
959         uint32 root;
960         // check if given Lba lays in the partition covered by VAT
961         if(Lba >= Vcb->NWA)
962             return Vcb->NWA;
963         if(Lba < (root = Vcb->Partitions[Vcb->VatPartNdx].PartitionRoot))
964             return Lba;
965         Map = &(Vcb->Vat[(i = Lba - root)]);
966         if((i < Vcb->VatCount) && (i=(*Map)) ) {
967             if(i != UDF_VAT_FREE_ENTRY) {
968                 return i + root;
969             } else {
970                 return 0x7fffffff;
971             }
972         }
973     }
974     return Lba;
975 } // end UDFRelocateSector()
976 
977 /*
978     This routine checks if the extent specified requires relocation
979  */
980 BOOLEAN
981 __fastcall
982 UDFAreSectorsRelocated(
983     IN PVCB Vcb,
984     IN uint32 Lba,
985     IN uint32 BlockCount
986     )
987 {
988 
989     if(Vcb->SparingTable) {
990         // use sparing table for relocation
991         uint32 i, BS, orig;
992         BS = Vcb->SparingBlockSize;
993         PSPARING_MAP Map;
994 
995         Map = Vcb->SparingTable;
996         for(i=0;i<Vcb->SparingCount;i++,Map++) {
997             if( ((Lba >= (orig = Map->origLocation)) && (Lba < orig + BS)) ||
998                 ((Lba+BlockCount-1 >= orig) && (Lba+BlockCount-1 < orig + BS)) ||
999                 ((orig >= Lba) && (orig < Lba+BlockCount)) ||
1000                 ((orig+BS >= Lba) && (orig+BS < Lba+BlockCount)) ) {
1001                 return TRUE;
1002             }
1003         }
1004     } else if(Vcb->Vat) {
1005         // use VAT for relocation
1006         uint32 i, root, j;
1007         uint32* Map;
1008         if(Lba < (root = Vcb->Partitions[Vcb->VatPartNdx].PartitionRoot))
1009             return FALSE;
1010         if(Lba+BlockCount >= Vcb->NWA)
1011             return TRUE;
1012         Map = &(Vcb->Vat[Lba-root/*+i*/]);
1013         for(i=0; i<BlockCount; i++, Map++) {
1014             if((j = (*Map)) &&
1015                (j != Lba-root+i) &&
1016                ((j != UDF_VAT_FREE_ENTRY) || ((Lba+i) < Vcb->LastLBA)))
1017                 return TRUE;
1018         }
1019     }
1020     return FALSE;
1021 } // end UDFAreSectorsRelocated()
1022 
1023 /*
1024     This routine builds mapping for relocated extent
1025     If relocation is not required (-1) will be returned
1026  */
1027 PEXTENT_MAP
1028 __fastcall
1029 UDFRelocateSectors(
1030     IN PVCB Vcb,
1031     IN uint32 Lba,
1032     IN uint32 BlockCount
1033     )
1034 {
1035     if(!UDFAreSectorsRelocated(Vcb, Lba, BlockCount)) return UDF_NO_EXTENT_MAP;
1036 
1037     PEXTENT_MAP Extent=NULL, Extent2;
1038     uint32 NewLba, LastLba, j, i;
1039     EXTENT_AD locExt;
1040 
1041     LastLba = UDFRelocateSector(Vcb, Lba);
1042     for(i=0, j=1; i<BlockCount; i++, j++) {
1043         // create new entry if the extent in not contigous
1044         if( ((NewLba = UDFRelocateSector(Vcb, Lba+i+1)) != (LastLba+1)) ||
1045             (i==(BlockCount-1)) ) {
1046             locExt.extLength = j << Vcb->BlockSizeBits;
1047             locExt.extLocation = LastLba-j+1;
1048             Extent2 = UDFExtentToMapping(&locExt);
1049             if(!Extent) {
1050                 Extent = Extent2;
1051             } else {
1052                 Extent = UDFMergeMappings(Extent, Extent2);
1053                 MyFreePool__(Extent2);
1054             }
1055             if(!Extent) return NULL;
1056             j = 0;
1057         }
1058         LastLba = NewLba;
1059     }
1060     return Extent;
1061 } // end UDFRelocateSectors()
1062 
1063