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
UDFVInit(IN PVCB Vcb)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
UDFVWaitQueued(PUDF_VERIFY_CTX VerifyCtx)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
UDFVRelease(IN PVCB Vcb)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
UDFVStoreBlock(IN PVCB Vcb,IN uint32 LBA,IN PVOID Buffer,PLIST_ENTRY Link)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
UDFVUpdateBlock(IN PVCB Vcb,IN PVOID Buffer,PUDF_VERIFY_ITEM vItem)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
UDFVRemoveBlock(PUDF_VERIFY_CTX VerifyCtx,PUDF_VERIFY_ITEM vItem)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
UDFVWrite(IN PVCB Vcb,IN void * Buffer,IN uint32 BCount,IN uint32 LBA,IN uint32 Flags)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
UDFVRead(IN PVCB Vcb,IN void * Buffer,IN uint32 BCount,IN uint32 LBA,IN uint32 Flags)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
UDFVForget(IN PVCB Vcb,IN uint32 BCount,IN uint32 LBA,IN uint32 Flags)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
UDFVWorkItem(PVOID Context)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
UDFVVerify(IN PVCB Vcb,IN ULONG Flags)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
UDFVFlush(IN PVCB Vcb)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
UDFCheckArea(IN PVCB Vcb,IN lba_t LBA,IN uint32 BCount)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
UDFRemapPacket(IN PVCB Vcb,IN uint32 Lba,IN BOOLEAN RemapSpared)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
UDFUnmapRange(IN PVCB Vcb,IN uint32 Lba,IN uint32 BCount)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
UDFRelocateSector(IN PVCB Vcb,IN uint32 Lba)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
UDFAreSectorsRelocated(IN PVCB Vcb,IN uint32 Lba,IN uint32 BlockCount)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
UDFRelocateSectors(IN PVCB Vcb,IN uint32 Lba,IN uint32 BlockCount)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