1*13128Ssam /* vfs_cluster.c 4.47 83/06/14 */ 28Sbill 39763Ssam #include "../machine/pte.h" 49763Ssam 58Sbill #include "../h/param.h" 68Sbill #include "../h/systm.h" 78Sbill #include "../h/dir.h" 88Sbill #include "../h/user.h" 98Sbill #include "../h/buf.h" 108Sbill #include "../h/conf.h" 118Sbill #include "../h/proc.h" 128Sbill #include "../h/seg.h" 138Sbill #include "../h/vm.h" 142045Swnj #include "../h/trace.h" 158Sbill 1691Sbill /* 178Sbill * Read in (if necessary) the block and return a buffer pointer. 188Sbill */ 198Sbill struct buf * 206563Smckusic bread(dev, blkno, size) 216563Smckusic dev_t dev; 226563Smckusic daddr_t blkno; 236563Smckusic int size; 248Sbill { 258Sbill register struct buf *bp; 268Sbill 278670S if (size == 0) 288670S panic("bread: size 0"); 296563Smckusic bp = getblk(dev, blkno, size); 308Sbill if (bp->b_flags&B_DONE) { 313199Swnj trace(TR_BREADHIT, dev, blkno); 328Sbill return(bp); 338Sbill } 348Sbill bp->b_flags |= B_READ; 358670S if (bp->b_bcount > bp->b_bufsize) 368670S panic("bread"); 378Sbill (*bdevsw[major(dev)].d_strategy)(bp); 383199Swnj trace(TR_BREADMISS, dev, blkno); 398039Sroot u.u_ru.ru_inblock++; /* pay for read */ 407015Smckusick biowait(bp); 418Sbill return(bp); 428Sbill } 438Sbill 448Sbill /* 458Sbill * Read in the block, like bread, but also start I/O on the 468Sbill * read-ahead block (which is not allocated to the caller) 478Sbill */ 488Sbill struct buf * 498592Sroot breada(dev, blkno, size, rablkno, rabsize) 506563Smckusic dev_t dev; 517114Smckusick daddr_t blkno; int size; 528592Sroot daddr_t rablkno; int rabsize; 538Sbill { 548Sbill register struct buf *bp, *rabp; 558Sbill 568Sbill bp = NULL; 577015Smckusick /* 587015Smckusick * If the block isn't in core, then allocate 597015Smckusick * a buffer and initiate i/o (getblk checks 607015Smckusick * for a cache hit). 617015Smckusick */ 628Sbill if (!incore(dev, blkno)) { 636563Smckusic bp = getblk(dev, blkno, size); 648Sbill if ((bp->b_flags&B_DONE) == 0) { 658Sbill bp->b_flags |= B_READ; 668670S if (bp->b_bcount > bp->b_bufsize) 678670S panic("breada"); 688Sbill (*bdevsw[major(dev)].d_strategy)(bp); 693199Swnj trace(TR_BREADMISS, dev, blkno); 708039Sroot u.u_ru.ru_inblock++; /* pay for read */ 717015Smckusick } else 723199Swnj trace(TR_BREADHIT, dev, blkno); 738Sbill } 747015Smckusick 757015Smckusick /* 767015Smckusick * If there's a read-ahead block, start i/o 777015Smckusick * on it also (as above). 787015Smckusick */ 798Sbill if (rablkno && !incore(dev, rablkno)) { 808592Sroot rabp = getblk(dev, rablkno, rabsize); 812045Swnj if (rabp->b_flags & B_DONE) { 828Sbill brelse(rabp); 833199Swnj trace(TR_BREADHITRA, dev, blkno); 842045Swnj } else { 858Sbill rabp->b_flags |= B_READ|B_ASYNC; 868670S if (rabp->b_bcount > rabp->b_bufsize) 878670S panic("breadrabp"); 888Sbill (*bdevsw[major(dev)].d_strategy)(rabp); 893199Swnj trace(TR_BREADMISSRA, dev, rablock); 908039Sroot u.u_ru.ru_inblock++; /* pay in advance */ 918Sbill } 928Sbill } 937015Smckusick 947015Smckusick /* 957114Smckusick * If block was in core, let bread get it. 967114Smckusick * If block wasn't in core, then the read was started 977114Smckusick * above, and just wait for it. 987015Smckusick */ 997114Smckusick if (bp == NULL) 1007114Smckusick return (bread(dev, blkno, size)); 1017015Smckusick biowait(bp); 1027114Smckusick return (bp); 1038Sbill } 1048Sbill 1058Sbill /* 1068Sbill * Write the buffer, waiting for completion. 1078Sbill * Then release the buffer. 1088Sbill */ 1098Sbill bwrite(bp) 1107015Smckusick register struct buf *bp; 1118Sbill { 1128Sbill register flag; 1138Sbill 1148Sbill flag = bp->b_flags; 1159857Ssam bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI); 1168Sbill if ((flag&B_DELWRI) == 0) 1178039Sroot u.u_ru.ru_oublock++; /* noone paid yet */ 1184033Swnj trace(TR_BWRITE, bp->b_dev, bp->b_blkno); 1198670S if (bp->b_bcount > bp->b_bufsize) 1208670S panic("bwrite"); 1218Sbill (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 1227015Smckusick 1237015Smckusick /* 1247015Smckusick * If the write was synchronous, then await i/o completion. 1257015Smckusick * If the write was "delayed", then we put the buffer on 1267015Smckusick * the q of blocks awaiting i/o completion status. 1277015Smckusick */ 1288Sbill if ((flag&B_ASYNC) == 0) { 1297015Smckusick biowait(bp); 1308Sbill brelse(bp); 1318Sbill } else if (flag & B_DELWRI) 1328Sbill bp->b_flags |= B_AGE; 1338Sbill } 1348Sbill 1358Sbill /* 1368Sbill * Release the buffer, marking it so that if it is grabbed 1378Sbill * for another purpose it will be written out before being 1388Sbill * given up (e.g. when writing a partial block where it is 1398Sbill * assumed that another write for the same block will soon follow). 1408Sbill * This can't be done for magtape, since writes must be done 1418Sbill * in the same order as requested. 1428Sbill */ 1438Sbill bdwrite(bp) 1447015Smckusick register struct buf *bp; 1458Sbill { 1462403Skre register int flags; 1478Sbill 1488Sbill if ((bp->b_flags&B_DELWRI) == 0) 1498039Sroot u.u_ru.ru_oublock++; /* noone paid yet */ 1502403Skre flags = bdevsw[major(bp->b_dev)].d_flags; 1512403Skre if(flags & B_TAPE) 1528Sbill bawrite(bp); 1538Sbill else { 1548Sbill bp->b_flags |= B_DELWRI | B_DONE; 1558Sbill brelse(bp); 1568Sbill } 1578Sbill } 1588Sbill 1598Sbill /* 1608Sbill * Release the buffer, start I/O on it, but don't wait for completion. 1618Sbill */ 1628Sbill bawrite(bp) 1637015Smckusick register struct buf *bp; 1648Sbill { 1658Sbill 1668Sbill bp->b_flags |= B_ASYNC; 1678Sbill bwrite(bp); 1688Sbill } 1698Sbill 1708Sbill /* 1717015Smckusick * Release the buffer, with no I/O implied. 1728Sbill */ 1738Sbill brelse(bp) 1747015Smckusick register struct buf *bp; 1758Sbill { 1762325Swnj register struct buf *flist; 1778Sbill register s; 1788Sbill 1797015Smckusick /* 1807015Smckusick * If someone's waiting for the buffer, or 1817015Smckusick * is waiting for a buffer wake 'em up. 1827015Smckusick */ 1838Sbill if (bp->b_flags&B_WANTED) 1848Sbill wakeup((caddr_t)bp); 1852325Swnj if (bfreelist[0].b_flags&B_WANTED) { 1862325Swnj bfreelist[0].b_flags &= ~B_WANTED; 1872325Swnj wakeup((caddr_t)bfreelist); 1888Sbill } 1892683Swnj if (bp->b_flags&B_ERROR) 1902683Swnj if (bp->b_flags & B_LOCKED) 1912683Swnj bp->b_flags &= ~B_ERROR; /* try again later */ 1922683Swnj else 1932683Swnj bp->b_dev = NODEV; /* no assoc */ 1947015Smckusick 1957015Smckusick /* 1967015Smckusick * Stick the buffer back on a free list. 1977015Smckusick */ 1988Sbill s = spl6(); 1998670S if (bp->b_bufsize <= 0) { 2008670S /* block has no buffer ... put at front of unused buffer list */ 2018670S flist = &bfreelist[BQ_EMPTY]; 2028670S binsheadfree(bp, flist); 2038670S } else if (bp->b_flags & (B_ERROR|B_INVAL)) { 2042325Swnj /* block has no info ... put at front of most free list */ 2058670S flist = &bfreelist[BQ_AGE]; 2067015Smckusick binsheadfree(bp, flist); 2078Sbill } else { 2082325Swnj if (bp->b_flags & B_LOCKED) 2092325Swnj flist = &bfreelist[BQ_LOCKED]; 2102325Swnj else if (bp->b_flags & B_AGE) 2112325Swnj flist = &bfreelist[BQ_AGE]; 2122325Swnj else 2132325Swnj flist = &bfreelist[BQ_LRU]; 2147015Smckusick binstailfree(bp, flist); 2158Sbill } 2168Sbill bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE); 2178Sbill splx(s); 2188Sbill } 2198Sbill 2208Sbill /* 2218Sbill * See if the block is associated with some buffer 2228Sbill * (mainly to avoid getting hung up on a wait in breada) 2238Sbill */ 2248Sbill incore(dev, blkno) 2257015Smckusick dev_t dev; 2267015Smckusick daddr_t blkno; 2278Sbill { 2288Sbill register struct buf *bp; 2292325Swnj register struct buf *dp; 2308Sbill 2316563Smckusic dp = BUFHASH(dev, blkno); 2322325Swnj for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) 2336563Smckusic if (bp->b_blkno == blkno && bp->b_dev == dev && 2347015Smckusick (bp->b_flags & B_INVAL) == 0) 23591Sbill return (1); 23691Sbill return (0); 2378Sbill } 2388Sbill 2398Sbill struct buf * 2406563Smckusic baddr(dev, blkno, size) 2416563Smckusic dev_t dev; 2426563Smckusic daddr_t blkno; 2436563Smckusic int size; 2448Sbill { 2458Sbill 2468Sbill if (incore(dev, blkno)) 2476563Smckusic return (bread(dev, blkno, size)); 2488Sbill return (0); 2498Sbill } 2508Sbill 2518Sbill /* 2528Sbill * Assign a buffer for the given block. If the appropriate 2538Sbill * block is already associated, return it; otherwise search 2548Sbill * for the oldest non-busy buffer and reassign it. 2555424Swnj * 2565424Swnj * We use splx here because this routine may be called 2575424Swnj * on the interrupt stack during a dump, and we don't 2585424Swnj * want to lower the ipl back to 0. 2598Sbill */ 2608Sbill struct buf * 2616563Smckusic getblk(dev, blkno, size) 2626563Smckusic dev_t dev; 2636563Smckusic daddr_t blkno; 2646563Smckusic int size; 2658Sbill { 2668670S register struct buf *bp, *dp; 2675424Swnj int s; 2688Sbill 2699763Ssam if ((unsigned)blkno >= 1 << (sizeof(int)*NBBY-PGSHIFT)) /* XXX */ 2701831Sbill blkno = 1 << ((sizeof(int)*NBBY-PGSHIFT) + 1); 2717015Smckusick /* 2727015Smckusick * Search the cache for the block. If we hit, but 2737015Smckusick * the buffer is in use for i/o, then we wait until 2747015Smckusick * the i/o has completed. 2757015Smckusick */ 2766563Smckusic dp = BUFHASH(dev, blkno); 2777015Smckusick loop: 2782325Swnj for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) { 2796563Smckusic if (bp->b_blkno != blkno || bp->b_dev != dev || 2802325Swnj bp->b_flags&B_INVAL) 2818Sbill continue; 2825424Swnj s = spl6(); 2838Sbill if (bp->b_flags&B_BUSY) { 2848Sbill bp->b_flags |= B_WANTED; 2858Sbill sleep((caddr_t)bp, PRIBIO+1); 2865424Swnj splx(s); 2878Sbill goto loop; 2888Sbill } 2895424Swnj splx(s); 2908Sbill notavail(bp); 2917188Sroot if (brealloc(bp, size) == 0) 2927188Sroot goto loop; 2938Sbill bp->b_flags |= B_CACHE; 2948Sbill return(bp); 2958Sbill } 29691Sbill if (major(dev) >= nblkdev) 29791Sbill panic("blkdev"); 2988670S bp = getnewbuf(); 2996563Smckusic bfree(bp); 3007015Smckusick bremhash(bp); 3017015Smckusick binshash(bp, dp); 3028Sbill bp->b_dev = dev; 3036563Smckusic bp->b_blkno = blkno; 3048670S bp->b_error = 0; 3057188Sroot if (brealloc(bp, size) == 0) 3067188Sroot goto loop; 3078Sbill return(bp); 3088Sbill } 3098Sbill 3108Sbill /* 3118Sbill * get an empty block, 3128Sbill * not assigned to any particular device 3138Sbill */ 3148Sbill struct buf * 3156563Smckusic geteblk(size) 3166563Smckusic int size; 3178Sbill { 3188670S register struct buf *bp, *flist; 3198Sbill 3208Sbill loop: 3218670S bp = getnewbuf(); 3228670S bp->b_flags |= B_INVAL; 3237015Smckusick bfree(bp); 3247015Smckusick bremhash(bp); 3258670S flist = &bfreelist[BQ_AGE]; 3268670S binshash(bp, flist); 3278Sbill bp->b_dev = (dev_t)NODEV; 3288670S bp->b_error = 0; 3297188Sroot if (brealloc(bp, size) == 0) 3307188Sroot goto loop; 3318Sbill return(bp); 3328Sbill } 3338Sbill 3348Sbill /* 3356563Smckusic * Allocate space associated with a buffer. 3369763Ssam * If can't get space, buffer is released 3376563Smckusic */ 3386563Smckusic brealloc(bp, size) 3396563Smckusic register struct buf *bp; 3406563Smckusic int size; 3416563Smckusic { 3426563Smckusic daddr_t start, last; 3436563Smckusic register struct buf *ep; 3446563Smckusic struct buf *dp; 3456563Smckusic int s; 3466563Smckusic 3476563Smckusic /* 3486563Smckusic * First need to make sure that all overlaping previous I/O 3496563Smckusic * is dispatched with. 3506563Smckusic */ 3516563Smckusic if (size == bp->b_bcount) 3527188Sroot return (1); 3537188Sroot if (size < bp->b_bcount) { 3547188Sroot if (bp->b_flags & B_DELWRI) { 3557188Sroot bwrite(bp); 3567188Sroot return (0); 3577188Sroot } 3587188Sroot if (bp->b_flags & B_LOCKED) 3597188Sroot panic("brealloc"); 3609763Ssam return (allocbuf(bp, size)); 3617188Sroot } 3627188Sroot bp->b_flags &= ~B_DONE; 3639763Ssam if (bp->b_dev == NODEV) 3649763Ssam return (allocbuf(bp, size)); 3657016Smckusick 3667188Sroot /* 3677188Sroot * Search cache for any buffers that overlap the one that we 3687188Sroot * are trying to allocate. Overlapping buffers must be marked 3697188Sroot * invalid, after being written out if they are dirty. (indicated 3707188Sroot * by B_DELWRI) A disk block must be mapped by at most one buffer 3717188Sroot * at any point in time. Care must be taken to avoid deadlocking 3727188Sroot * when two buffer are trying to get the same set of disk blocks. 3737188Sroot */ 3747188Sroot start = bp->b_blkno; 37512644Ssam last = start + btodb(size) - 1; 3766563Smckusic dp = BUFHASH(bp->b_dev, bp->b_blkno); 3776563Smckusic loop: 3786563Smckusic for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) { 3797188Sroot if (ep == bp || ep->b_dev != bp->b_dev || (ep->b_flags&B_INVAL)) 3806563Smckusic continue; 3817188Sroot /* look for overlap */ 3827188Sroot if (ep->b_bcount == 0 || ep->b_blkno > last || 38312644Ssam ep->b_blkno + btodb(ep->b_bcount) <= start) 3847188Sroot continue; 3856563Smckusic s = spl6(); 3866563Smckusic if (ep->b_flags&B_BUSY) { 3876563Smckusic ep->b_flags |= B_WANTED; 3886563Smckusic sleep((caddr_t)ep, PRIBIO+1); 3898670S splx(s); 3906563Smckusic goto loop; 3916563Smckusic } 3928670S splx(s); 3937188Sroot notavail(ep); 3946563Smckusic if (ep->b_flags & B_DELWRI) { 3956563Smckusic bwrite(ep); 3966563Smckusic goto loop; 3976563Smckusic } 3987188Sroot ep->b_flags |= B_INVAL; 3997188Sroot brelse(ep); 4006563Smckusic } 4019763Ssam return (allocbuf(bp, size)); 4028670S } 4038670S 4048670S /* 4058670S * Find a buffer which is available for use. 4068670S * Select something from a free list. 4078670S * Preference is to AGE list, then LRU list. 4088670S */ 4098670S struct buf * 4108670S getnewbuf() 4118670S { 4128670S register struct buf *bp, *dp; 4138670S int s; 4148670S 4158670S loop: 4168670S s = spl6(); 4179763Ssam #ifndef sun 4188670S for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--) 4199763Ssam #else 4209763Ssam for (dp = &bfreelist[BQ_EMPTY]; dp > bfreelist; dp--) 4219763Ssam #endif 4228670S if (dp->av_forw != dp) 4238670S break; 4248670S if (dp == bfreelist) { /* no free blocks */ 4258670S dp->b_flags |= B_WANTED; 4268670S sleep((caddr_t)dp, PRIBIO+1); 42712170Ssam splx(s); 4288670S goto loop; 4298670S } 4308670S splx(s); 4318670S bp = dp->av_forw; 4328670S notavail(bp); 4338670S if (bp->b_flags & B_DELWRI) { 4348670S bp->b_flags |= B_ASYNC; 4358670S bwrite(bp); 4368670S goto loop; 4378670S } 4388670S trace(TR_BRELSE, bp->b_dev, bp->b_blkno); 4398670S bp->b_flags = B_BUSY; 4408670S return (bp); 4418670S } 4428670S 4438670S /* 4448Sbill * Wait for I/O completion on the buffer; return errors 4458Sbill * to the user. 4468Sbill */ 4477015Smckusick biowait(bp) 4486563Smckusic register struct buf *bp; 4498Sbill { 4505431Sroot int s; 4518Sbill 4525431Sroot s = spl6(); 4538Sbill while ((bp->b_flags&B_DONE)==0) 4548Sbill sleep((caddr_t)bp, PRIBIO); 4555431Sroot splx(s); 45611841Ssam if (u.u_error == 0) /* XXX */ 45711841Ssam u.u_error = geterror(bp); 4588Sbill } 4598Sbill 4608Sbill /* 461*13128Ssam * Mark I/O complete on a buffer. 462*13128Ssam * If someone should be called, e.g. the pageout 463*13128Ssam * daemon, do so. Otherwise, wake up anyone 464*13128Ssam * waiting for it. 4658Sbill */ 4667015Smckusick biodone(bp) 4677015Smckusick register struct buf *bp; 4688Sbill { 4698Sbill 470420Sbill if (bp->b_flags & B_DONE) 4717015Smckusick panic("dup biodone"); 4728Sbill bp->b_flags |= B_DONE; 4739763Ssam if (bp->b_flags & B_CALL) { 4749763Ssam bp->b_flags &= ~B_CALL; 4759763Ssam (*bp->b_iodone)(bp); 4769763Ssam return; 4779763Ssam } 4788Sbill if (bp->b_flags&B_ASYNC) 4798Sbill brelse(bp); 4808Sbill else { 4818Sbill bp->b_flags &= ~B_WANTED; 4828Sbill wakeup((caddr_t)bp); 4838Sbill } 4848Sbill } 4858Sbill 4868Sbill /* 4878670S * Insure that no part of a specified block is in an incore buffer. 4888670S */ 4898670S blkflush(dev, blkno, size) 4908670S dev_t dev; 4918670S daddr_t blkno; 4928670S long size; 4938670S { 4948670S register struct buf *ep; 4958670S struct buf *dp; 4968670S daddr_t start, last; 4978670S int s; 4988670S 4998670S start = blkno; 50012644Ssam last = start + btodb(size) - 1; 5018670S dp = BUFHASH(dev, blkno); 5028670S loop: 5038670S for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) { 5048670S if (ep->b_dev != dev || (ep->b_flags&B_INVAL)) 5058670S continue; 5068670S /* look for overlap */ 5078670S if (ep->b_bcount == 0 || ep->b_blkno > last || 50812644Ssam ep->b_blkno + btodb(ep->b_bcount) <= start) 5098670S continue; 5108670S s = spl6(); 5118670S if (ep->b_flags&B_BUSY) { 5128670S ep->b_flags |= B_WANTED; 5138670S sleep((caddr_t)ep, PRIBIO+1); 5148670S splx(s); 5158670S goto loop; 5168670S } 5178670S if (ep->b_flags & B_DELWRI) { 5188670S splx(s); 5198670S notavail(ep); 5208670S bwrite(ep); 5218670S goto loop; 5228670S } 5238670S splx(s); 5248670S } 5258670S } 5268670S 5278670S /* 528*13128Ssam * Make sure all write-behind blocks 5298Sbill * on dev (or NODEV for all) 5308Sbill * are flushed out. 5318Sbill * (from umount and update) 5328Sbill */ 5338Sbill bflush(dev) 5347015Smckusick dev_t dev; 5358Sbill { 5368Sbill register struct buf *bp; 5372325Swnj register struct buf *flist; 5385431Sroot int s; 5398Sbill 5408Sbill loop: 5415431Sroot s = spl6(); 5428670S for (flist = bfreelist; flist < &bfreelist[BQ_EMPTY]; flist++) 5432325Swnj for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) { 5447015Smckusick if ((bp->b_flags & B_DELWRI) == 0) 5457015Smckusick continue; 5467015Smckusick if (dev == NODEV || dev == bp->b_dev) { 5478Sbill bp->b_flags |= B_ASYNC; 5488Sbill notavail(bp); 5498Sbill bwrite(bp); 55012173Ssam splx(s); 5518Sbill goto loop; 5528Sbill } 5538Sbill } 5545431Sroot splx(s); 5558Sbill } 5568Sbill 5578Sbill /* 5588Sbill * Pick up the device's error number and pass it to the user; 5598Sbill * if there is an error but the number is 0 set a generalized 5608Sbill * code. Actually the latter is always true because devices 5618Sbill * don't yet return specific errors. 5628Sbill */ 5638Sbill geterror(bp) 5647015Smckusick register struct buf *bp; 5658Sbill { 5667723Swnj int error = 0; 5678Sbill 5688Sbill if (bp->b_flags&B_ERROR) 5697723Swnj if ((error = bp->b_error)==0) 5707723Swnj return (EIO); 5717723Swnj return (error); 5728Sbill } 5732299Skre 5742299Skre /* 5752299Skre * Invalidate in core blocks belonging to closed or umounted filesystem 5762299Skre * 5772299Skre * This is not nicely done at all - the buffer ought to be removed from the 5782299Skre * hash chains & have its dev/blkno fields clobbered, but unfortunately we 5792299Skre * can't do that here, as it is quite possible that the block is still 5802299Skre * being used for i/o. Eventually, all disc drivers should be forced to 5812299Skre * have a close routine, which ought ensure that the queue is empty, then 5822299Skre * properly flush the queues. Until that happy day, this suffices for 5832299Skre * correctness. ... kre 5842299Skre */ 5852299Skre binval(dev) 5867015Smckusick dev_t dev; 5872299Skre { 5882361Skre register struct buf *bp; 5892361Skre register struct bufhd *hp; 5902361Skre #define dp ((struct buf *)hp) 5912299Skre 5922361Skre for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++) 5932361Skre for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) 5942361Skre if (bp->b_dev == dev) 5952361Skre bp->b_flags |= B_INVAL; 5962299Skre } 597