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