home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / alt_os / mint / mfs6011 / source / minixfs / cache.c < prev    next >
C/C++ Source or Header  |  1994-12-30  |  9KB  |  364 lines

  1. /* This file is part of 'minixfs' Copyright 1991,1992,1993 S.N. Henson */
  2.  
  3. #include "minixfs.h"
  4. #include "global.h"
  5. #include "proto.h"
  6.  
  7. /* For this kind of file system a cache is absolutely essential,
  8. without it your hard-disk will sound like a buzz-saw .... the 
  9. idea is fairly simple , for every block requested if it is not in 
  10. the cache load it in at the current position .Then return a 
  11. pointer to the block . Additionally all writes go to the cache if
  12. an entry exists for the specified block . This means that when a 
  13. cache entry is overwritten we must write out the entry if it is
  14. 'dirty' , the function l_sync() writes out the entire cache along
  15. with the zone and inode bitmaps. However for an increase in performance, 
  16. three caches are used , one for inodes one for directories and indirection 
  17. blocks , one for files , these are kmalloc()'ed at the same time so that 
  18. one follows the other in memory , this simplifies cache-flushing for example.
  19. */
  20.  
  21. /* Initialise cache */
  22. int init_cache()
  23. {
  24.     cache *ctemp;
  25.     long i;
  26.         /* Start with system cache */
  27.     ctemp=Kmalloc((icache_size+scache_size+ucache_size)*(SIZEOF(cache)+BLOCK_SIZE));
  28.     if(!ctemp)
  29.     {
  30.         CCONWS("Can't Allocate Cache: Using defaults");
  31.         ctemp=Kmalloc((ICACHE_SIZE+SCACHE_SIZE+UCACHE_SIZE)*(SIZEOF(cache)+BLOCK_SIZE));
  32.         if(!ctemp)
  33.         {
  34.             CCONWS("Can't Allocate Default Cache: Minixfs not installed");
  35.             return 1;
  36.         }
  37.         icache_size=ICACHE_SIZE;
  38.         ucache_size=UCACHE_SIZE;
  39.         scache_size=SCACHE_SIZE;
  40.     }
  41.  
  42.     syscache.start=ctemp;
  43.     syscache.end=&ctemp[scache_size];
  44.     syscache.pos=syscache.start;
  45.     icache.start=syscache.end;
  46.     icache.end=&icache.start[icache_size];
  47.     icache.pos=icache.start;
  48.     usrcache.start=icache.end;
  49.     usrcache.pos=usrcache.start;
  50.     usrcache.end=&usrcache.start[ucache_size];
  51.     /* Invalidate all entries , initialise buffer pointers */
  52.     for(ctemp=syscache.start,i=0;ctemp!=usrcache.end;ctemp++,i++)
  53.     {
  54.         ctemp->buffer= ((bufr *)(usrcache.end))+i;
  55.         ctemp->status=0;
  56.     }
  57.  
  58. /* Initialise dummy guess */
  59.     dummy.iguess=icache.start;
  60.     dummy.zguess=usrcache.start;
  61.     dummy.izguess=syscache.start;
  62.     dummy.dizguess=syscache.start;
  63.  
  64.     return 0;
  65. }
  66.  
  67.  
  68. void
  69. l_sync()
  70. {
  71.     cache *p;
  72.     int i;
  73. /* Write out dirty cache entries */
  74.     for(p=syscache.start;p!=usrcache.end;p+=writeout(&usrcache,p)) continue;
  75.  
  76.     /* Now inode and zone bitmaps */
  77.     for(i=0;i<NUM_DRIVES;i++)
  78.     {
  79.     if(super_ptr[i]) {
  80.         super_info *psblk;
  81.         psblk=super_ptr[i];
  82.         if(psblk==DFS) continue;
  83.  
  84.         if(psblk->idirty && psblk->zdirty)
  85.             crwabs(3,psblk->ibitmap,psblk->sblk.s_imap_blks+
  86.                 psblk->sblk.s_zmap_blks,2,i);
  87.         else
  88.         {
  89.             if(psblk->idirty)
  90.                crwabs(3,psblk->ibitmap,psblk->sblk.s_imap_blks,2,i);
  91.              if(psblk->zdirty)
  92.                  crwabs(3,psblk->zbitmap,psblk->sblk.s_zmap_blks,
  93.                            psblk->sblk.s_imap_blks+2,i);
  94.         }
  95.         psblk->idirty=0;
  96.         psblk->zdirty=0;
  97.     }
  98.     }
  99. }
  100.  
  101. /* Return cache entry for numr,drive if it exists or NULL, this uses a 'guess'
  102.  * pointer for the caches: start at the point an entry was last found, this
  103.  * should be reduce cache searching a bit.
  104.  */
  105.  
  106. cache *in_cache(numr,drive,control,guess)
  107. long numr;
  108. int drive;
  109. cache_control *control;
  110. cache **guess;
  111. {
  112.     cache *p;
  113.  
  114.     if(guess)
  115.     {
  116.  
  117.         for(p=*guess;p!=control->end;p++)
  118.             if((p->block==numr) && (p->drive==drive) && p->status)
  119.                             return (*guess=p);
  120.         for(p=control->start;p!=*guess;p++)
  121.             if((p->block==numr) && (p->drive==drive) && p->status)
  122.                             return (*guess=p);
  123.     }
  124.     else
  125.     {
  126.         for(p=control->start;p!=control->end;p++)
  127.             if((p->block==numr) && (p->drive==drive) && p->status)
  128.                             return p;
  129.     }
  130.  
  131.     return NULL;
  132. }
  133.  
  134. /* Return a pointer to block numr,drive loading and updating cache if needed */
  135.  
  136. bufr *cget_block(numr,drive,control)
  137. long numr;
  138. int drive;
  139. cache_control * control;
  140. {
  141.     return(cache_get(numr,drive,control,NOGUESS)->buffer);
  142. }
  143.  
  144. #if 1
  145. /* super-simple `least recently used' strategy... after a cache hit
  146.  * advance control->pos if this buffer otherwise would be reused soon.
  147.  */
  148. #define pos_up(pp, control) do { \
  149.         long size = ((char *)control->end)-((char *)control->start), \
  150.                 d = ((char *)pp)-((char *)control->pos); \
  151.         if (d < 0) d += size; \
  152.         if (d < size/4) control->pos = pp+1; \
  153.     } while (0)
  154. #else
  155. #define pos_up(pp, control)
  156. #endif
  157.  
  158. /* Return a pointer to a cache entry buffer for numr,drive with the dirty 
  159.  * flag set, if not in cache create a new entry but do *not* read in data
  160.  * from the disk, this is useful for example when an entire disk block will
  161.  * be written in one go.
  162.  */
  163.  
  164. cache *cache_put(numr,drive,control)
  165. long numr;
  166. int drive;
  167. cache_control *control;
  168. {
  169.     cache *p;
  170.     if(!(p=in_cache(numr,drive,control,NOGUESS)))
  171.     {
  172.         if(control!=&icache) chk_zone(numr,1,drive);
  173.         if(control->pos==control->end) control->pos=control->start;
  174.         p=control->pos++;
  175.         writeout(control,p);
  176.         p->drive=drive;
  177.         p->block=numr;
  178.     } else
  179.         pos_up (p, control);
  180.  
  181.     p->status=2;
  182.     return (p);
  183. }
  184.  
  185. cache *
  186. cache_get(numr,drive,control,guess)
  187. long numr;
  188. int drive;
  189. cache_control *control;
  190. cache **guess;
  191. {
  192.     cache *p;
  193.     if( (p=in_cache(numr,drive,control,guess)) ) {
  194.         pos_up (p, control);
  195.         return(p);
  196.     }
  197.     /* Read block in */
  198.     if(control->pos==control->end)
  199.         control->pos=control->start;
  200.     /* Write out dirty entries before they are overwritten */
  201.     if(control->pos->status >1 ) writeout(control,control->pos);
  202.  
  203.     /* This is the only check done on I/O into cache. If invalid
  204.      * blocks can never enter the cache then all should be OK
  205.      * later on. Unless the memory gets trashed. Interesting hack:
  206.      * if iblock is in range and all inode blocks are used (as will
  207.      * usually be the case) then the inode number producing it should
  208.      * be in range too, so no checking on inode numbers need be done.
  209.      */
  210.  
  211.     if(control==&icache) chk_iblock(numr,super_ptr[drive]);
  212.     else chk_zone(numr,1,drive);
  213.  
  214.  
  215.     crwabs(2,control->pos->buffer,1,numr,drive);
  216.     /* Update Cache */
  217.     control->pos->drive=drive;
  218.     control->pos->block=numr;
  219.     control->pos->status=1;
  220.  
  221.     if(guess) *guess=control->pos;
  222.     return ( control->pos++ );
  223. }
  224.  
  225. /* Write out block, search cache and if 'hit' update and mark as dirty 
  226.  * after copying the data across, otherwise flush current entry.
  227.  */
  228.  
  229. int
  230. cput_block(numr,drive,buf,control)
  231. long numr;
  232. int drive;
  233. void *buf;
  234. cache_control *control;
  235. {
  236.     cache *p;
  237.  
  238.     if( (p=in_cache(numr,drive,control,NOGUESS)) ){
  239.         if(buf!=p->buffer) bcopy(buf,p->buffer,BLOCK_SIZE);
  240.         p->status=2;
  241.         pos_up (p, control);
  242.         return 0;
  243.     }
  244.  
  245.     if(control->pos==control->end) control->pos=control->start;
  246.     writeout(control,control->pos);
  247.  
  248.     if(control!=&icache) chk_zone(numr,1,drive);
  249.  
  250.     bcopy(buf,control->pos->buffer,BLOCK_SIZE);
  251.     /* Update Cache */
  252.     control->pos->drive=drive;
  253.     control->pos->block=numr;
  254.     control->pos->status=2;
  255.     control->pos++;
  256.     return 0;
  257. }
  258.  
  259. /* From the cache-pointer 'p' write out dirty entries that are consecutive
  260.  * all in one go, this should cut down on I/O quite a lot.
  261.  */
  262.  
  263. #define DEBUG_CACHE
  264.  
  265. long writeout(control,p)
  266. cache_control *control;
  267. cache *p;
  268. {
  269.     cache *q;
  270.     long i;
  271.  
  272.     if(p->status<2) return 1;
  273.     /* Determined how many blocks are consecutive */
  274.     for(q=p,i=0;q!=control->end;q++,i++)
  275.     {
  276. #ifdef DEBUG_CACHE
  277.         /* Check block boundaries */
  278.         if(q->status)
  279.         {
  280.             if( (q >= icache.start) && (q < icache.end))
  281.                 chk_iblock(q->block,super_ptr[q->drive]);
  282.             else chk_zone(q->block,1,q->drive);
  283.         }
  284. #endif
  285.         if( (q->drive!=p->drive) || (q->block!=p->block+i) || 
  286.             (q->status < 2) ) break;
  287.  
  288.         q->status=1;
  289.     }
  290.  
  291.     crwabs(3,p->buffer,i,p->block,p->drive);
  292.  
  293.     return i;
  294. }
  295.  
  296. /* From the current cache position, read up to the num zones pointed to by
  297.  * zone_list in. Flush the cache and read in as much as possible in one go.
  298.  * Stop at first non-consecutive zone.
  299.  */
  300.  
  301. long readin(zone_list,num,drive,control)
  302. long *zone_list;
  303. int num;
  304. int drive;
  305. cache_control *control;
  306. {
  307.     cache *p;
  308.     int i,j;
  309.  
  310.     if(!*zone_list) return 0;
  311.     for(i=1;i<num;i++)if(zone_list[i]!=zone_list[0]+i) break;
  312.     if(control->pos==control->end) control->pos=control->start;
  313.     i=min(control->end-control->pos,i);
  314.     /* If any entries already in cache, forget it */
  315.     for(p=control->start;p!=control->end;p++) if( (p->drive==drive) 
  316.     && (p->block >= zone_list[0]) && (p->block < zone_list[0]+i) ) 
  317.         return 0;
  318.  
  319.     /* Write out at least 'i' entries */
  320.     for(p=control->pos; p < control->pos+i ; )
  321.     {
  322.         if(p->status < 2) p++;
  323.         else p+=writeout(control,p);
  324.     }
  325.  
  326.     chk_zone(zone_list[0],i,drive);
  327.  
  328.     crwabs(2,control->pos->buffer,i,zone_list[0],drive);
  329.     for(p=control->pos,j=0;j<i;j++,p++)
  330.     {
  331.         p->block=zone_list[j];
  332.         p->drive=drive;
  333.         p->status=1;
  334.     }
  335.     control->pos+=i;
  336.     return i;
  337. }
  338.  
  339. /* Invalidate all cache entries for a given drive */
  340.  
  341. void m_invalidate(drv)
  342. int drv;
  343. {
  344.     int warned=0;
  345.     cache *p;
  346.     super_info *psblk;
  347.     for(p=syscache.start;p!=usrcache.end;p++)
  348.     if(p->drive==drv && p->status)
  349.     {
  350.         if(p->status==2 && !warned++)
  351.         ALERT("Cache entry not written out when drive %c invalidated",drv+'A');
  352.         p->status=0;
  353.     }
  354.     psblk=super_ptr[drv];
  355.     if(psblk==DFS) return;
  356.  
  357.     if(psblk->idirty)
  358.         ALERT("Inode bitmap not written out when drive %c invalidated",drv+'A');
  359.     if(psblk->zdirty)
  360.         ALERT("Zone bitmap not written out when drive %c invalidated",drv+'A');
  361.     psblk->idirty=0;
  362.     psblk->zdirty=0;
  363. }
  364.