00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <routix/device.h>
00016 #include <routix/kalloc.h>
00017 #include <routix/kstdio.h>
00018 #include <routix/task.h>
00019 #include <routix/system.h>
00020 #include <fs/blockcache.h>
00021 #include <sys/list.h>
00022 #include <routix/atomic.h>
00023
00024 #define RUNSTATS 1
00025
00026
00027 #define PAGE_SIZE 4096
00028
00029 #define MAXHASHENTRIES 10
00030 #define HASH(maxhash,dev,sector) ( (dev+sector)%maxhash )
00031 #define HASH_DEVICE(dev) (dev)
00032
00033 #define MAKE_MULTIPLE(original,multiple) ((original)+((multiple)-(original)%(multiple)))
00034
00035
00036 static LIST_NEW(block_cache_t) free_list;
00037 static LIST_NEW(block_cache_t) cached_list[MAXHASHENTRIES];
00038 static LIST_NEW(block_cache_t) drv_req_list[MAXDEVICEENTRIES];
00039
00040
00041
00042
00043
00044
00045
00046
00047 #define MAX_BLOCKCACHE_MEM 5
00048
00049
00050
00051 static inline byte *alloc_block();
00052 static inline block_cache_t *alloc_header();
00053 static inline block_cache_t *getfreeblock(void);
00054
00055
00056 static void show_cached_list(void);
00057
00058
00059 void start_block_cache(int totalmemory)
00060 {
00061 int blocks;
00062 int tmp;
00063
00064
00065
00066
00067 LIST_INIT(free_list);
00068
00069 for (tmp=0; tmp<MAXHASHENTRIES; tmp++) {
00070 LIST_INIT(cached_list[tmp]);
00071 }
00072
00073 for (tmp=0; tmp<MAXDEVICEENTRIES; tmp++) {
00074 LIST_INIT(drv_req_list[tmp]);
00075 }
00076
00077
00078 totalmemory *= 1024*1024;
00079
00080
00081
00082
00083
00084 blocks=totalmemory*MAX_BLOCKCACHE_MEM/(100*BLOCK_SIZE);
00085 blocks=MAKE_MULTIPLE(blocks,PAGE_SIZE/BLOCK_SIZE);
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 kprintf("Inicializando Cache de Bloques con %d bloques\n",blocks);
00098 byte *datablock;
00099 block_cache_t *headerblock;
00100
00101 while ( blocks-- ) {
00102
00103
00104 datablock=alloc_block();
00105
00106
00107 headerblock=alloc_header();
00108
00109
00110 BLOCK_CACHE_BUFFER(headerblock)=datablock;
00111 BLOCK_CACHE_STATE(headerblock)=UNLOCKED;
00112 BLOCK_CACHE_LOCKCOUNT(headerblock)=0;
00113 LIST_CLEAN(BLOCK_CACHE_PENDING_PROCESS_LIST(headerblock));
00114
00115
00116
00117 LIST_ADD(free_list,free,headerblock);
00118
00119 }
00120
00121 }
00122
00123
00124 inline static byte *alloc_block()
00125 {
00126 static byte *actual_page=NULL;
00127 static unsigned short int used_blocks=0;
00128
00129 if ( (actual_page==NULL) || (used_blocks == (PAGE_SIZE/BLOCK_SIZE)) ) {
00130 actual_page=(byte *) kmalloc_page();
00131 used_blocks=0;
00132 }
00133
00134 return( (byte *) (actual_page+BLOCK_SIZE*(used_blocks++)) );
00135
00136 }
00137
00138 inline static block_cache_t *alloc_header()
00139 {
00140 static block_cache_t *actual_page=NULL;
00141 static unsigned short int used_headers=0;
00142
00143 if ( (actual_page==NULL) || (used_headers >= (PAGE_SIZE/sizeof(block_cache_t))) ) {
00144 actual_page=(block_cache_t *) kmalloc_page();
00145 used_headers=0;
00146 }
00147
00148 used_headers++;
00149
00150 return(actual_page++);
00151 }
00152
00153
00154 inline block_cache_t *getrequest(device_t device)
00155 {
00156
00157
00158 return( LIST_FIRST(drv_req_list[HASH_DEVICE(device)]) );
00159 }
00160
00161
00162 inline void endrequest(block_cache_t *block)
00163 {
00164
00165 LIST_DEL(drv_req_list[HASH_DEVICE( BLOCK_CACHE_DEVICE(block) )],driver_request_list,block);
00166
00167
00168 despertar_task( LIST_FIRST(BLOCK_CACHE_PENDING_PROCESS_LIST(block)) );
00169
00170 }
00171
00176 inline void sendrequest(block_cache_t *block)
00177 {
00178
00179
00180 LIST_ADD_TAIL(drv_req_list[ HASH_DEVICE( BLOCK_CACHE_DEVICE(block) ) ],driver_request_list,block);
00181
00182
00183
00184 }
00185
00186
00287 int cache_read(device_t device, word sector, unsigned int start, char *dstbuffer, unsigned int len)
00288 {
00289
00290 block_cache_t *tmp;
00291 task_struct_t *proc_iterator;
00292
00293 #ifdef RUNSTATS
00294 long long counter;
00295
00296 if ( getvar("debugcache") == 1 )
00297 kprintf("cache_read: starting, dev: %d, sector: %d, start: %d buffer: 0x%x len: %d\n",device,sector,start,dstbuffer,len);
00298
00299 if ( getvar("debugcache") == 2 )
00300 rdtscl(counter);
00301 #endif
00302
00303 restart:
00304
00305 if ( getvar("debugcache") == 1 )
00306 kprintf("cache_read: buscando bloque en la lista de cache\n");
00307
00308 START_ATOMIC_OPERATION;
00309
00310 #ifdef RUNSTATS
00311 if ( getvar("debugcache")==1 )
00312 show_cached_list();
00313 #endif
00314
00315
00316 LIST_FOREACH(tmp,cached_list[ HASH(MAXHASHENTRIES,device,sector) ], cached)
00317 if ( BLOCK_CACHE_DEVICE(tmp)==device && BLOCK_CACHE_SECTOR(tmp)==sector )
00318 break;
00319
00320
00321 if ( tmp ) {
00322
00323 #ifdef RUNSTATS
00324 if ( getvar("debugcache") == 1 )
00325 kprintf("cache_read: cache hit !\n");
00326 #endif
00327
00328
00329 if ( BLOCK_CACHE_STATE(tmp)==WRITE_LOCKED || BLOCK_CACHE_STATE(tmp)==SYNCRONIZING ) {
00330
00331
00332
00333 LIST_ADD_TAIL(BLOCK_CACHE_PENDING_PROCESS_LIST(tmp),io_pending,actual);
00334
00335
00336
00337 dormir_task(actual);
00338
00339 FINISH_ATOMIC_OPERATION;
00340
00341
00342 _reschedule();
00343
00344
00345
00346
00347 goto restart;
00348 }
00349
00350
00351 else {
00352
00353
00354
00355 if ( BLOCK_CACHE_STATE(tmp)==UNLOCKED ) {
00356 BLOCK_CACHE_STATE(tmp)=READ_LOCKED;
00357 LIST_DEL(free_list,free,tmp);
00358 BLOCK_CACHE_LOCKCOUNT(tmp)=0;
00359 }
00360 #ifdef RUNSTATS
00361 else {
00362 if ( getvar("debugcache")==3 )
00363 kprintf("Sector: %d relockeando!\n",sector);
00364
00365 }
00366 #endif
00367
00368 }
00369
00370 }
00371
00372
00373 else {
00374
00375 #ifdef RUNSTATS
00376 if ( getvar("debugcache") == 1 )
00377 kprintf("cache_read: cache miss(%d) ",sector);
00378 #endif
00379
00380
00381
00382 tmp=getfreeblock();
00383
00384 #ifdef RUNSTATS
00385 if ( getvar("debugcache") == 1 )
00386 kprintf("cache_read: bloque obtenido de la free list 0x%x\n",tmp);
00387
00388 if ( getvar("debugcache") == 1 )
00389 kprintf("cache_read: eliminamos este nuevo bloque de la free list\n");
00390 #endif
00391
00392
00393 BLOCK_CACHE_STATE(tmp)=SYNCRONIZING;
00394
00395
00396 BLOCK_CACHE_DEVICE(tmp)=device;
00397 BLOCK_CACHE_SECTOR(tmp)=sector;
00398 BLOCK_CACHE_OPERATION(tmp)=IOREAD;
00399
00400
00401 #ifdef RUNSTATS
00402 if ( getvar("debugcache") == 1 ) {
00403 kprintf("cache_read: lo LOCKEAMOS\n");
00404 kprintf("cache_read: entrada numero %d en la cached list\n",HASH(MAXHASHENTRIES,device,sector));
00405 }
00406 #endif
00407
00408
00409 LIST_ADD_TAIL(cached_list[ HASH(MAXHASHENTRIES,device,sector) ],cached,tmp);
00410
00411
00412 #ifdef RUNSTATS
00413 if ( getvar("debugcache") == 1 )
00414 kprintf("cache_read: y lo insertamos al final de la lista de bloques cacheados\n");
00415 #endif
00416
00417
00418 LIST_ADD(BLOCK_CACHE_PENDING_PROCESS_LIST(tmp),io_pending,actual);
00419
00420 #ifdef RUNSTATS
00421 if ( getvar("debugcache") == 1 ) {
00422 kprintf("cache_read: insertamos el proceso actual en la lista de procesos con io pendiente\n");
00423 kprintf("cache_read: enviamos el request\n");
00424 }
00425 #endif
00426
00427
00428
00429 sendrequest(tmp);
00430
00431
00432 dormir_task(actual);
00433
00434 #ifdef RUNSTATS
00435 if ( getvar("debugcache") == 1 )
00436 kprintf("cache_read: nos dormimos\n");
00437 #endif
00438
00439 FINISH_ATOMIC_OPERATION;
00440
00441
00442 _reschedule();
00443
00444 START_ATOMIC_OPERATION;
00445
00446 #ifdef RUNSTATS
00447 if ( getvar("debugcache") == 1 )
00448 kprintf("cache_read: nos despertamos !\n");
00449 #endif
00450
00451
00452 LIST_DEL(BLOCK_CACHE_PENDING_PROCESS_LIST(tmp),io_pending,actual);
00453
00454
00455 LIST_FOREACH(proc_iterator,BLOCK_CACHE_PENDING_PROCESS_LIST(tmp),io_pending) {
00456 despertar_task(proc_iterator);
00457 }
00458
00459
00460 LIST_CLEAN(BLOCK_CACHE_PENDING_PROCESS_LIST(tmp));
00461
00462
00463
00464
00465
00466
00467
00468
00469 if ( BLOCK_CACHE_RETURN(tmp) == -1 ) {
00470
00471 LIST_DEL(cached_list[ HASH(MAXHASHENTRIES,device,sector) ],cached,tmp);
00472
00473 LIST_ADD(free_list,free,tmp);
00474
00475 FINISH_ATOMIC_OPERATION;
00476
00477 return -1;
00478
00479 }
00480
00481 }
00482
00483
00484 BLOCK_CACHE_LOCKCOUNT(tmp)++;
00485
00486
00487 BLOCK_CACHE_STATE(tmp)=READ_LOCKED;
00488
00489 FINISH_ATOMIC_OPERATION;
00490
00491 char *origin = BLOCK_CACHE_BUFFER(tmp) + start;
00492
00493
00494 while ( len-- )
00495 *dstbuffer++ = *origin++;
00496
00497 START_ATOMIC_OPERATION;
00498
00499
00500 BLOCK_CACHE_LOCKCOUNT(tmp)--;
00501
00502 if ( BLOCK_CACHE_LOCKCOUNT(tmp)==0 ) {
00503
00504
00505 BLOCK_CACHE_STATE(tmp)=UNLOCKED;
00506
00507
00508 LIST_ADD_TAIL(free_list,free,tmp);
00509
00510
00511
00512 LIST_FOREACH(proc_iterator,BLOCK_CACHE_PENDING_PROCESS_LIST(tmp),io_pending)
00513 despertar_task(proc_iterator);
00514
00515 LIST_CLEAN(BLOCK_CACHE_PENDING_PROCESS_LIST(tmp));
00516
00517 }
00518
00519 #ifdef RUNSTATS
00520 if ( getvar("debugcache") == 2 ) {
00521 long long int counterfinal;
00522 rdtscl(counterfinal);
00523 kprintf("0x%llx ",counterfinal-counter);
00524 }
00525 #endif
00526
00527 FINISH_ATOMIC_OPERATION;
00528
00529 return 1;
00530
00531 }
00532
00533
00562 static inline block_cache_t *getfreeblock(void)
00563 {
00564
00565 byte found=0;
00566 block_cache_t *tmp;
00567
00568 do {
00569
00570
00571 tmp=LIST_FIRST(free_list);
00572
00573
00574 LIST_DEL(free_list,free,tmp);
00575
00576
00577 if ( BLOCK_CACHE_STATE(tmp)==DIRTY ) {
00578
00579 }
00580
00581
00582 else
00583 found=1;
00584
00585 } while ( ! found );
00586
00587 return tmp;
00588
00589 }
00590
00591
00592 static void show_cached_list(void)
00593 {
00594 int iter;
00595 block_cache_t *tmp;
00596 char state;
00597
00598 int cached_blocks=0;
00599
00600 for(iter=0; iter<MAXHASHENTRIES; iter++) {
00601
00602 kprintf("Entry %d: ",iter);
00603
00604 LIST_FOREACH(tmp,cached_list[iter],cached) {
00605 cached_blocks++;
00606
00607 switch ( BLOCK_CACHE_STATE(tmp) ) {
00608
00609 case READ_LOCKED:
00610 state='R';
00611 break;
00612
00613 case WRITE_LOCKED:
00614 state='W';
00615 break;
00616
00617 case UNLOCKED:
00618 state='U';
00619 break;
00620
00621 case SYNCRONIZING:
00622 state='S';
00623 break;
00624
00625 default:
00626 state='?';
00627 break;
00628
00629
00630 }
00631
00632 if ( BLOCK_CACHE_STATE(tmp)==READ_LOCKED ) {
00633 kprintf(" %d(%c%d)", BLOCK_CACHE_SECTOR(tmp),state,BLOCK_CACHE_LOCKCOUNT(tmp));
00634 }
00635 else {
00636 kprintf(" %d(%c)", BLOCK_CACHE_SECTOR(tmp),state);
00637 }
00638 }
00639
00640 kprintf("\n");
00641
00642 }
00643
00644 kprintf("%d bloques cacheados\n",cached_blocks);
00645
00646 }