[UDFS]
[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 // 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 uint32* 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 UDFVWorkItem(
541 PUDF_VERIFY_REQ VerifyReq
542 )
543 {
544 PVCB Vcb = VerifyReq->Vcb;
545 ULONG ReadBytes;
546 // OSSTATUS RC;
547 ULONG i;
548
549 ReadBytes = (ULONG)Vcb;
550 #if 1
551 if(Vcb->SparingCountFree) {
552 WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE);
553 for(i=0; i<VerifyReq->nReq; i++) {
554 UDFTIOVerify(Vcb,
555 VerifyReq->Buffer, // Target buffer
556 VerifyReq->vr[i].BCount << Vcb->BlockSizeBits,
557 VerifyReq->vr[i].lba,
558 &ReadBytes,
559 PH_TMP_BUFFER | PH_VCB_IN_RETLEN /*| PH_LOCK_CACHE*/);
560 }
561 WCacheEODirect__(&(Vcb->FastCache), Vcb);
562 } else {
563 for(i=0; i<VerifyReq->nReq; i++) {
564 UDFPrint(("!!! No more space for remap !!!\n"));
565 UDFPrint((" try del from verify cache @ %x\n", VerifyReq->vr[i].lba));
566 UDFVRead(Vcb, VerifyReq->Buffer, VerifyReq->vr[i].BCount, VerifyReq->vr[i].lba,
567 PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER);
568 }
569 }
570 #else
571 for(i=0; i<VerifyReq->nReq; i++) {
572 if(Vcb->SparingCountFree) {
573 WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE);
574 RC = UDFTIOVerify(Vcb,
575 VerifyReq->Buffer, // Target buffer
576 VerifyReq->vr[i].BCount << Vcb->BlockSizeBits,
577 VerifyReq->vr[i].lba,
578 &ReadBytes,
579 PH_TMP_BUFFER | PH_VCB_IN_RETLEN /*| PH_LOCK_CACHE*/);
580 WCacheEODirect__(&(Vcb->FastCache), Vcb);
581 } else {
582 UDFPrint(("!!! No more space for remap !!!\n"));
583 UDFPrint((" try del from verify cache @ %x\n", VerifyReq->vr[i].lba));
584 RC = UDFVRead(Vcb, VerifyReq->Buffer, VerifyReq->vr[i].BCount, VerifyReq->vr[i].lba,
585 PH_FORGET_VERIFIED | PH_READ_VERIFY_CACHE | PH_TMP_BUFFER);
586 }
587 }
588 #endif
589 DbgFreePool(VerifyReq->Buffer);
590 DbgFreePool(VerifyReq);
591 InterlockedDecrement((PLONG)&(Vcb->VerifyCtx.QueuedCount));
592 UDFPrint((" QueuedCount = %d\n", Vcb->VerifyCtx.QueuedCount));
593 UDFPrint((" Setting event...\n"));
594 KeSetEvent(&(Vcb->VerifyCtx.vrfEvent), 0, FALSE);
595 return;
596 } // end UDFVWorkItem()
597
598 VOID
599 UDFVVerify(
600 IN PVCB Vcb,
601 IN ULONG Flags
602 )
603 {
604 PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
605 PLIST_ENTRY Link;
606 PUDF_VERIFY_ITEM vItem;
607 PUDF_VERIFY_REQ VerifyReq = NULL;
608 ULONG len, max_len=0;
609 lba_t prev_lba;
610 //PUCHAR tmp_buff;
611 ULONG i;
612 BOOLEAN do_vrf = FALSE;
613
614 if(!VerifyCtx->VInited) {
615 return;
616 }
617 if(VerifyCtx->QueuedCount) {
618 if(Flags & UFD_VERIFY_FLAG_WAIT) {
619 UDFPrint((" wait for verify flush\n"));
620 goto wait;
621 }
622 UDFPrint((" verify flush already queued\n"));
623 return;
624 }
625
626 if(!(Flags & (UFD_VERIFY_FLAG_FORCE | UFD_VERIFY_FLAG_BG))) {
627 if(VerifyCtx->ItemCount < UDF_MAX_VERIFY_CACHE) {
628 return;
629 }
630
631 }
632 if(!(Flags & UFD_VERIFY_FLAG_LOCKED)) {
633 UDFAcquireResourceExclusive(&(VerifyCtx->VerifyLock), TRUE);
634 }
635
636 if(Flags & UFD_VERIFY_FLAG_FORCE) {
637 i = VerifyCtx->ItemCount;
638 } else {
639 if(VerifyCtx->ItemCount >= UDF_MAX_VERIFY_CACHE) {
640 i = VerifyCtx->ItemCount - UDF_VERIFY_CACHE_LOW;
641 } else {
642 i = min(UDF_VERIFY_CACHE_GRAN, VerifyCtx->ItemCount);
643 }
644 }
645
646 Link = VerifyCtx->vrfList.Flink;
647 prev_lba = -2;
648 len = 0;
649
650 while(i) {
651 ASSERT(Link != &(VerifyCtx->vrfList));
652 /*
653 if(Link == &(VerifyCtx->vrfList)) {
654 if(!len)
655 break;
656 i=1;
657 goto queue_req;
658 }
659 */
660 vItem = CONTAINING_RECORD( Link, UDF_VERIFY_ITEM, vrfList );
661 Link = Link->Flink;
662
663 //
664 if(!vItem->queued && (prev_lba+len == vItem->lba)) {
665 vItem->queued = TRUE;
666 len++;
667 } else {
668 if(len) {
669 do_vrf = TRUE;
670 } else {
671 len = 1;
672 prev_lba = vItem->lba;
673 }
674 }
675 if((i == 1) && len) {
676 do_vrf = TRUE;
677 }
678 if(len >= 0x100) {
679 do_vrf = TRUE;
680 }
681 if(do_vrf) {
682 //queue_req:
683 if(!VerifyReq) {
684 VerifyReq = (PUDF_VERIFY_REQ)DbgAllocatePoolWithTag(NonPagedPool, sizeof(UDF_VERIFY_REQ), 'bNWD');
685 if(VerifyReq) {
686 RtlZeroMemory(VerifyReq, sizeof(UDF_VERIFY_REQ));
687 VerifyReq->Vcb = Vcb;
688 }
689 }
690 if(VerifyReq) {
691
692 VerifyReq->vr[VerifyReq->nReq].lba = prev_lba;
693 VerifyReq->vr[VerifyReq->nReq].BCount = len;
694 VerifyReq->nReq++;
695 if(max_len < len) {
696 max_len = len;
697 }
698
699 if((VerifyReq->nReq >= MAX_VREQ_RANGES) || (i == 1)) {
700
701 VerifyReq->Buffer = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, max_len * Vcb->BlockSize, 'bNWD');
702 if(VerifyReq->Buffer) {
703 InterlockedIncrement((PLONG)&(VerifyCtx->QueuedCount));
704 #ifndef _CONSOLE
705 ExInitializeWorkItem( &(VerifyReq->VerifyItem),
706 (PWORKER_THREAD_ROUTINE) UDFVWorkItem,
707 VerifyReq );
708 ExQueueWorkItem( &(VerifyReq->VerifyItem), CriticalWorkQueue );
709 #else
710 UDFVWorkItem(VerifyReq);
711 #endif
712 } else {
713 DbgFreePool(VerifyReq);
714 }
715 VerifyReq = NULL;
716 max_len = 0;
717 } else {
718 }
719 }
720 len = 1;
721 prev_lba = vItem->lba;
722 do_vrf = FALSE;
723 }
724 i--;
725 }
726
727 if(!(Flags & UFD_VERIFY_FLAG_LOCKED)) {
728 UDFReleaseResource(&(VerifyCtx->VerifyLock));
729 }
730 if(Flags & UFD_VERIFY_FLAG_WAIT) {
731 wait:
732 UDFPrint(("UDFVVerify: wait for completion\n"));
733 UDFVWaitQueued(VerifyCtx);
734 }
735
736 return;
737 } // end UDFVVerify()
738
739 VOID
740 UDFVFlush(
741 IN PVCB Vcb
742 )
743 {
744 PUDF_VERIFY_CTX VerifyCtx = &Vcb->VerifyCtx;
745
746 if(!VerifyCtx->VInited) {
747 return;
748 }
749
750 UDFPrint(("UDFVFlush: wait for completion\n"));
751 UDFVWaitQueued(VerifyCtx);
752
753 UDFVVerify(Vcb, UFD_VERIFY_FLAG_FORCE);
754
755 UDFPrint(("UDFVFlush: wait for completion (2)\n"));
756 UDFVWaitQueued(VerifyCtx);
757 } // end UDFVFlush()
758
759 BOOLEAN
760 __fastcall
761 UDFCheckArea(
762 IN PVCB Vcb,
763 IN lba_t LBA,
764 IN uint32 BCount
765 )
766 {
767 uint8* buff;
768 OSSTATUS RC;
769 uint32 ReadBytes;
770 uint32 i, d;
771 BOOLEAN ext_ok = TRUE;
772 EXTENT_MAP Map[2];
773 uint32 PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits;
774
775 buff = (uint8*)DbgAllocatePoolWithTag(NonPagedPool, Vcb->WriteBlockSize, 'bNWD' );
776 if(buff) {
777 for(i=0; i<BCount; i+=d) {
778 if(!((LBA+i) & (PS-1)) &&
779 (i+PS <= BCount)) {
780 d = PS;
781 } else {
782 d = 1;
783 }
784 RC = UDFTRead(Vcb,
785 buff,
786 d << Vcb->BlockSizeBits,
787 LBA+i,
788 &ReadBytes,
789 PH_TMP_BUFFER);
790
791 if(RC != STATUS_SUCCESS) {
792 Map[0].extLocation = LBA+i;
793 Map[0].extLength = d << Vcb->BlockSizeBits;
794 UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(Map[0]), AS_DISCARDED | AS_BAD); // free
795 ext_ok = FALSE;
796 }
797 }
798 DbgFreePool(buff);
799 }
800 return ext_ok;
801 } // end UDFCheckArea()
802
803 /*
804 This routine remaps sectors from bad packet
805 */
806 OSSTATUS
807 __fastcall
808 UDFRemapPacket(
809 IN PVCB Vcb,
810 IN uint32 Lba,
811 IN BOOLEAN RemapSpared
812 )
813 {
814 uint32 i, max, BS, orig;
815 PSPARING_MAP Map;
816 BOOLEAN verified = FALSE;
817
818 if(Vcb->SparingTable) {
819
820 max = Vcb->SparingCount;
821 BS = Vcb->SparingBlockSize;
822
823 // use sparing table for relocation
824 if(Vcb->SparingCountFree == (ULONG)-1) {
825 UDFPrint(("calculate free spare areas\n"));
826 re_check:
827 UDFPrint(("verify spare area\n"));
828 Vcb->SparingCountFree = 0;
829 Map = Vcb->SparingTable;
830 for(i=0;i<max;i++,Map++) {
831 if(Map->origLocation == SPARING_LOC_AVAILABLE) {
832 if(UDFCheckArea(Vcb, Map->mappedLocation, BS)) {
833 Vcb->SparingCountFree++;
834 } else {
835 UDFPrint(("initial check: bad spare block @ %x\n", Map->mappedLocation));
836 Map->origLocation = SPARING_LOC_CORRUPTED;
837 Vcb->SparingTableModified = TRUE;
838 }
839 }
840 }
841 }
842 if(!Vcb->SparingCountFree) {
843 UDFPrint(("sparing table full\n"));
844 return STATUS_DISK_FULL;
845 }
846
847 Map = Vcb->SparingTable;
848 Lba &= ~(BS-1);
849 for(i=0;i<max;i++,Map++) {
850 orig = Map->origLocation;
851 if(Lba == (orig & ~(BS-1)) ) {
852 // already remapped
853
854 UDFPrint(("remap remapped: bad spare block @ %x\n", Map->mappedLocation));
855 if(!verified) {
856 verified = TRUE;
857 goto re_check;
858 }
859
860 if(!RemapSpared) {
861 return STATUS_SHARING_VIOLATION;
862 } else {
863 // look for another remap area
864 Map->origLocation = SPARING_LOC_CORRUPTED;
865 Vcb->SparingTableModified = TRUE;
866 Vcb->SparingCountFree--;
867 break;
868 }
869 }
870 }
871 Map = Vcb->SparingTable;
872 for(i=0;i<max;i++,Map++) {
873 if(Map->origLocation == SPARING_LOC_AVAILABLE) {
874 UDFPrint(("remap %x -> %x\n", Lba, Map->mappedLocation));
875 Map->origLocation = Lba;
876 Vcb->SparingTableModified = TRUE;
877 Vcb->SparingCountFree--;
878 return STATUS_SUCCESS;
879 }
880 }
881 UDFPrint(("sparing table full\n"));
882 return STATUS_DISK_FULL;
883 }
884 return STATUS_UNSUCCESSFUL;
885 } // end UDFRemapPacket()
886
887 /*
888 This routine releases sector mapping when entire packet is marked as free
889 */
890 OSSTATUS
891 __fastcall
892 UDFUnmapRange(
893 IN PVCB Vcb,
894 IN uint32 Lba,
895 IN uint32 BCount
896 )
897 {
898 uint32 i, max, BS, orig;
899 PSPARING_MAP Map;
900
901 if(Vcb->SparingTable) {
902 // use sparing table for relocation
903
904 max = Vcb->SparingCount;
905 BS = Vcb->SparingBlockSize;
906 Map = Vcb->SparingTable;
907 for(i=0;i<max;i++,Map++) {
908 orig = Map->origLocation;
909 switch(orig) {
910 case SPARING_LOC_AVAILABLE:
911 case SPARING_LOC_CORRUPTED:
912 continue;
913 }
914 if(orig >= Lba &&
915 (orig+BS) <= (Lba+BCount)) {
916 // unmap
917 UDFPrint(("unmap %x -> %x\n", orig, Map->mappedLocation));
918 Map->origLocation = SPARING_LOC_AVAILABLE;
919 Vcb->SparingTableModified = TRUE;
920 Vcb->SparingCountFree++;
921 }
922 }
923 }
924 return STATUS_SUCCESS;
925 } // end UDFUnmapRange()
926
927 /*
928 This routine returns physical address for relocated sector
929 */
930 uint32
931 __fastcall
932 UDFRelocateSector(
933 IN PVCB Vcb,
934 IN uint32 Lba
935 )
936 {
937 uint32 i, max, BS, orig;
938
939 if(Vcb->SparingTable) {
940 // use sparing table for relocation
941 uint32 _Lba;
942 PSPARING_MAP Map = Vcb->SparingTable;
943
944 max = Vcb->SparingCount;
945 BS = Vcb->SparingBlockSize;
946 _Lba = Lba & ~(BS-1);
947 for(i=0;i<max;i++,Map++) {
948 orig = Map->origLocation;
949 if(_Lba == (orig & ~(BS-1)) ) {
950 //if( (Lba >= (orig = Map->origLocation)) && (Lba < orig + BS) ) {
951 return Map->mappedLocation + Lba - orig;
952 }
953 }
954 } else if(Vcb->Vat) {
955 // use VAT for relocation
956 uint32* Map = Vcb->Vat;
957 uint32 root;
958 // check if given Lba lays in the partition covered by VAT
959 if(Lba >= Vcb->NWA)
960 return Vcb->NWA;
961 if(Lba < (root = Vcb->Partitions[Vcb->VatPartNdx].PartitionRoot))
962 return Lba;
963 Map = &(Vcb->Vat[(i = Lba - root)]);
964 if((i < Vcb->VatCount) && (i=(*Map)) ) {
965 if(i != UDF_VAT_FREE_ENTRY) {
966 return i + root;
967 } else {
968 return 0x7fffffff;
969 }
970 }
971 }
972 return Lba;
973 } // end UDFRelocateSector()
974
975 /*
976 This routine checks if the extent specified requires relocation
977 */
978 BOOLEAN
979 __fastcall
980 UDFAreSectorsRelocated(
981 IN PVCB Vcb,
982 IN uint32 Lba,
983 IN uint32 BlockCount
984 )
985 {
986
987 if(Vcb->SparingTable) {
988 // use sparing table for relocation
989 uint32 i, BS, orig;
990 BS = Vcb->SparingBlockSize;
991 PSPARING_MAP Map;
992
993 Map = Vcb->SparingTable;
994 for(i=0;i<Vcb->SparingCount;i++,Map++) {
995 if( ((Lba >= (orig = Map->origLocation)) && (Lba < orig + BS)) ||
996 ((Lba+BlockCount-1 >= orig) && (Lba+BlockCount-1 < orig + BS)) ||
997 ((orig >= Lba) && (orig < Lba+BlockCount)) ||
998 ((orig+BS >= Lba) && (orig+BS < Lba+BlockCount)) ) {
999 return TRUE;
1000 }
1001 }
1002 } else if(Vcb->Vat) {
1003 // use VAT for relocation
1004 uint32 i, root, j;
1005 uint32* Map;
1006 if(Lba < (root = Vcb->Partitions[Vcb->VatPartNdx].PartitionRoot))
1007 return FALSE;
1008 if(Lba+BlockCount >= Vcb->NWA)
1009 return TRUE;
1010 Map = &(Vcb->Vat[Lba-root/*+i*/]);
1011 for(i=0; i<BlockCount; i++, Map++) {
1012 if((j = (*Map)) &&
1013 (j != Lba-root+i) &&
1014 ((j != UDF_VAT_FREE_ENTRY) || ((Lba+i) < Vcb->LastLBA)))
1015 return TRUE;
1016 }
1017 }
1018 return FALSE;
1019 } // end UDFAreSectorsRelocated()
1020
1021 /*
1022 This routine builds mapping for relocated extent
1023 If relocation is not required (-1) will be returned
1024 */
1025 PEXTENT_MAP
1026 __fastcall
1027 UDFRelocateSectors(
1028 IN PVCB Vcb,
1029 IN uint32 Lba,
1030 IN uint32 BlockCount
1031 )
1032 {
1033 if(!UDFAreSectorsRelocated(Vcb, Lba, BlockCount)) return UDF_NO_EXTENT_MAP;
1034
1035 PEXTENT_MAP Extent=NULL, Extent2;
1036 uint32 NewLba, LastLba, j, i;
1037 EXTENT_AD locExt;
1038
1039 LastLba = UDFRelocateSector(Vcb, Lba);
1040 for(i=0, j=1; i<BlockCount; i++, j++) {
1041 // create new entry if the extent in not contigous
1042 if( ((NewLba = UDFRelocateSector(Vcb, Lba+i+1)) != (LastLba+1)) ||
1043 (i==(BlockCount-1)) ) {
1044 locExt.extLength = j << Vcb->BlockSizeBits;
1045 locExt.extLocation = LastLba-j+1;
1046 Extent2 = UDFExtentToMapping(&locExt);
1047 if(!Extent) {
1048 Extent = Extent2;
1049 } else {
1050 Extent = UDFMergeMappings(Extent, Extent2);
1051 MyFreePool__(Extent2);
1052 }
1053 if(!Extent) return NULL;
1054 j = 0;
1055 }
1056 LastLba = NewLba;
1057 }
1058 return Extent;
1059 } // end UDFRelocateSectors()
1060