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