1*7504Sroot /* lfs_inode.c 4.19 82/07/24 */ 224Sbill 324Sbill #include "../h/param.h" 424Sbill #include "../h/systm.h" 524Sbill #include "../h/mount.h" 624Sbill #include "../h/dir.h" 724Sbill #include "../h/user.h" 824Sbill #include "../h/inode.h" 96569Smckusic #include "../h/fs.h" 1024Sbill #include "../h/conf.h" 1124Sbill #include "../h/buf.h" 1224Sbill #include "../h/inline.h" 13*7504Sroot #ifdef QUOTA 14*7504Sroot #include "../h/quota.h" 15*7504Sroot #endif 1624Sbill 1724Sbill #define INOHSZ 63 187334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 197334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 207334Skre #else 2124Sbill #define INOHASH(dev,ino) (((dev)+(ino))%INOHSZ) 227334Skre #endif 2324Sbill 247334Skre union ihead { /* inode LRU cache, Chris Maltby */ 257334Skre union ihead *ih_head[2]; 267334Skre struct inode *ih_chain[2]; 277334Skre } ihead[INOHSZ]; 287334Skre 297334Skre struct inode *ifreeh, **ifreet; 307334Skre 3124Sbill /* 3224Sbill * Initialize hash links for inodes 3324Sbill * and build inode free list. 3424Sbill */ 3524Sbill ihinit() 3624Sbill { 3724Sbill register int i; 382737Swnj register struct inode *ip = inode; 397334Skre register union ihead *ih = ihead; 4024Sbill 417334Skre for (i = INOHSZ; --i >= 0; ih++) { 427334Skre ih->ih_head[0] = ih; 437334Skre ih->ih_head[1] = ih; 447334Skre } 457334Skre ifreeh = ip; 467334Skre ifreet = &ip->i_freef; 477334Skre ip->i_freeb = &ifreeh; 487334Skre ip->i_forw = ip; 497334Skre ip->i_back = ip; 507334Skre for (i = ninode; --i > 0; ) { 517334Skre ++ip; 527334Skre ip->i_forw = ip; 537334Skre ip->i_back = ip; 547334Skre *ifreet = ip; 557334Skre ip->i_freeb = ifreet; 567334Skre ifreet = &ip->i_freef; 577334Skre } 587334Skre ip->i_freef = NULL; 5924Sbill } 6024Sbill 617334Skre #ifdef notdef 6224Sbill /* 637334Skre * Find an inode if it is incore. 647334Skre * This is the equivalent, for inodes, 657334Skre * of ``incore'' in bio.c or ``pfind'' in subr.c. 667334Skre */ 677334Skre struct inode * 687334Skre ifind(dev, ino) 697334Skre dev_t dev; 707334Skre ino_t ino; 717334Skre { 727334Skre register struct inode *ip; 737334Skre register union ihead *ih; 747334Skre 757334Skre ih = &ihead[INOHASH(dev, ino)]; 767334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 777334Skre if (ino==ip->i_number && dev==ip->i_dev) 787334Skre return (ip); 797334Skre return ((struct inode *)0); 807334Skre } 817334Skre #endif notdef 827334Skre 837334Skre /* 8424Sbill * Look up an inode by device,inumber. 8524Sbill * If it is in core (in the inode structure), 8624Sbill * honor the locking protocol. 8724Sbill * If it is not in core, read it in from the 8824Sbill * specified device. 8924Sbill * If the inode is mounted on, perform 9024Sbill * the indicated indirection. 9124Sbill * In all cases, a pointer to a locked 9224Sbill * inode structure is returned. 9324Sbill * 9424Sbill * panic: no imt -- if the mounted file 9524Sbill * system is not in the mount table. 9624Sbill * "cannot happen" 9724Sbill */ 9824Sbill struct inode * 996569Smckusic iget(dev, fs, ino) 1004818Swnj dev_t dev; 1016569Smckusic register struct fs *fs; 1024818Swnj ino_t ino; 10324Sbill { 1047335Skre register struct inode *ip; 1057335Skre register union ihead *ih; 10624Sbill register struct mount *mp; 10724Sbill register struct buf *bp; 10824Sbill register struct dinode *dp; 1097334Skre register struct inode *iq; 11024Sbill 11124Sbill loop: 1126569Smckusic if (getfs(dev) != fs) 1136569Smckusic panic("iget: bad fs"); 1147334Skre ih = &ihead[INOHASH(dev, ino)]; 1157334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 1164818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 1174818Swnj if ((ip->i_flag&ILOCK) != 0) { 11824Sbill ip->i_flag |= IWANT; 11924Sbill sleep((caddr_t)ip, PINOD); 12024Sbill goto loop; 12124Sbill } 1224818Swnj if ((ip->i_flag&IMOUNT) != 0) { 1236569Smckusic for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 1247334Skre if(mp->m_inodp == ip) { 1257334Skre dev = mp->m_dev; 1267334Skre fs = mp->m_bufp->b_un.b_fs; 1277334Skre ino = ROOTINO; 1287334Skre goto loop; 1297334Skre } 13024Sbill panic("no imt"); 13124Sbill } 1327334Skre if (ip->i_count == 0) { /* ino on free list */ 1337334Skre if (iq = ip->i_freef) 1347334Skre iq->i_freeb = ip->i_freeb; 1357334Skre else 1367334Skre ifreet = ip->i_freeb; 1377334Skre *ip->i_freeb = iq; 1387334Skre ip->i_freef = NULL; 1397334Skre ip->i_freeb = NULL; 1407334Skre } 14124Sbill ip->i_count++; 14224Sbill ip->i_flag |= ILOCK; 14324Sbill return(ip); 14424Sbill } 1457334Skre 1467334Skre if ((ip = ifreeh) == NULL) { 1472933Swnj tablefull("inode"); 14824Sbill u.u_error = ENFILE; 14924Sbill return(NULL); 15024Sbill } 1517334Skre if (iq = ip->i_freef) 1527334Skre iq->i_freeb = &ifreeh; 1537334Skre ifreeh = iq; 1547334Skre ip->i_freef = NULL; 1557334Skre ip->i_freeb = NULL; 1567334Skre /* 1577334Skre * Now to take inode off the hash chain it was on 1587334Skre * (initially, or after an iflush, it is on a "hash chain" 1597334Skre * consisting entirely of itself, and pointed to by no-one, 1607334Skre * but that doesn't matter), and put it on the chain for 1617334Skre * its new (ino, dev) pair 1627334Skre */ 1637335Skre remque(ip); 1647335Skre insque(ip, ih); 1657492Skre #ifdef QUOTA 1667492Skre dqrele(ip->i_dquot); 1677492Skre #endif 16824Sbill ip->i_dev = dev; 1696569Smckusic ip->i_fs = fs; 17024Sbill ip->i_number = ino; 17124Sbill ip->i_flag = ILOCK; 17224Sbill ip->i_count++; 1736569Smckusic ip->i_lastr = 0; 1746569Smckusic bp = bread(dev, fsbtodb(fs, itod(fs, ino)), fs->fs_bsize); 17524Sbill /* 17624Sbill * Check I/O errors 17724Sbill */ 1784818Swnj if ((bp->b_flags&B_ERROR) != 0) { 17924Sbill brelse(bp); 1807334Skre /* 1817334Skre * the inode doesn't contain anything useful, so it would 1827334Skre * be misleading to leave it on its hash chain. 1837334Skre * 'iput' will take care of putting it back on the free list. 1847334Skre */ 1857335Skre remque(ip); 1867334Skre ip->i_forw = ip; 1877334Skre ip->i_back = ip; 1887334Skre /* 1897334Skre * we also loose its inumber, just in case (as iput 1907334Skre * doesn't do that any more) - but as it isn't on its 1917334Skre * hash chain, I doubt if this is really necessary .. kre 1927334Skre * (probably the two methods are interchangable) 1937334Skre */ 1947334Skre ip->i_number = 0; 1957492Skre #ifdef QUOTA 1967492Skre ip->i_dquot = NODQUOT; 1977492Skre #endif 19824Sbill iput(ip); 19924Sbill return(NULL); 20024Sbill } 20124Sbill dp = bp->b_un.b_dino; 2026569Smckusic dp += itoo(fs, ino); 2036569Smckusic ip->i_ic = dp->di_ic; 20424Sbill brelse(bp); 2057492Skre #ifdef QUOTA 2067492Skre if (ip->i_mode == 0) 2077492Skre ip->i_dquot = NODQUOT; 2087492Skre else 2097492Skre ip->i_dquot = inoquota(ip); 2107492Skre #endif 2116569Smckusic return (ip); 21224Sbill } 21324Sbill 214*7504Sroot int badinum = -1; 21524Sbill /* 21624Sbill * Decrement reference count of 21724Sbill * an inode structure. 21824Sbill * On the last reference, 21924Sbill * write the inode out and if necessary, 22024Sbill * truncate and deallocate the file. 22124Sbill */ 22224Sbill iput(ip) 2234818Swnj register struct inode *ip; 22424Sbill { 2257118Smckusick 2267118Smckusick if ((ip->i_flag & ILOCK) == 0) 2277118Smckusick panic("iput"); 228*7504Sroot /* XXX */ 229*7504Sroot if (ip->i_number == badinum && (ip->i_mode&IFMT) == IFCHR && 230*7504Sroot (major(ip->i_dev) != 3 || minor(ip->i_dev) != 2)) 231*7504Sroot panic("/dev/null"); 232*7504Sroot /* XXX */ 2337118Smckusick iunlock(ip); 2347118Smckusick irele(ip); 2357118Smckusick } 2367118Smckusick 2377118Smckusick irele(ip) 2387118Smckusick register struct inode *ip; 2397118Smckusick { 24024Sbill register int i, x; 24124Sbill register struct inode *jp; 2426569Smckusic int mode; 24324Sbill 2444818Swnj if (ip->i_count == 1) { 24524Sbill ip->i_flag |= ILOCK; 2464818Swnj if (ip->i_nlink <= 0) { 24724Sbill itrunc(ip); 2486569Smckusic mode = ip->i_mode; 24924Sbill ip->i_mode = 0; 2507351Skre ip->i_rdev = 0; 25124Sbill ip->i_flag |= IUPD|ICHG; 2526569Smckusic ifree(ip, ip->i_number, mode); 2537492Skre #ifdef QUOTA 2547492Skre chkiq(ip->i_dev, ip, ip->i_uid, 0); 2557492Skre dqrele(ip->i_dquot); 2567492Skre ip->i_dquot = NODQUOT; 2577492Skre #endif 25824Sbill } 2591203Sbill IUPDAT(ip, &time, &time, 0); 2607118Smckusick iunlock(ip); 2617334Skre ip->i_flag = 0; 2627334Skre /* 2637334Skre * Put the inode on the end of the free list. 2647334Skre * Possibly in some cases it would be better to 2657334Skre * put the inode at the head of the free list, 2667334Skre * (eg: where i_mode == 0 || i_number == 0) 2677334Skre * but I will think about that later .. kre 2687334Skre * (i_number is rarely 0 - only after an i/o error in iget, 2697334Skre * where i_mode == 0, the inode will probably be wanted 2707334Skre * again soon for an ialloc, so possibly we should keep it) 2717334Skre */ 2727334Skre if (ifreeh) { 2737334Skre *ifreet = ip; 2747334Skre ip->i_freeb = ifreet; 27524Sbill } else { 2767334Skre ifreeh = ip; 2777334Skre ip->i_freeb = &ifreeh; 27824Sbill } 2797334Skre ip->i_freef = NULL; 2807334Skre ifreet = &ip->i_freef; 2817118Smckusick } 28224Sbill ip->i_count--; 28324Sbill } 28424Sbill 28524Sbill /* 28624Sbill * Check accessed and update flags on 28724Sbill * an inode structure. 28824Sbill * If any is on, update the inode 28924Sbill * with the current time. 2901203Sbill * If waitfor is given, then must insure 2911203Sbill * i/o order so wait for write to complete. 29224Sbill */ 2931203Sbill iupdat(ip, ta, tm, waitfor) 2944818Swnj register struct inode *ip; 2954818Swnj time_t *ta, *tm; 2964818Swnj int waitfor; 29724Sbill { 29824Sbill register struct buf *bp; 29924Sbill struct dinode *dp; 3006569Smckusic register struct fs *fp; 30124Sbill 3026569Smckusic fp = ip->i_fs; 3036569Smckusic if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) { 3046569Smckusic if (fp->fs_ronly) 30524Sbill return; 3066569Smckusic bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 3076569Smckusic fp->fs_bsize); 30824Sbill if (bp->b_flags & B_ERROR) { 30924Sbill brelse(bp); 31024Sbill return; 31124Sbill } 3124818Swnj if (ip->i_flag&IACC) 3136569Smckusic ip->i_atime = *ta; 3144818Swnj if (ip->i_flag&IUPD) 3156569Smckusic ip->i_mtime = *tm; 3164818Swnj if (ip->i_flag&ICHG) 3176569Smckusic ip->i_ctime = time; 31824Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 3197343Skre dp = bp->b_un.b_dino + itoo(fp, ip->i_number); 3207343Skre dp->di_ic = ip->i_ic; 3211203Sbill if (waitfor) 3221203Sbill bwrite(bp); 3231203Sbill else 3241203Sbill bdwrite(bp); 32524Sbill } 32624Sbill } 32724Sbill 32824Sbill /* 32924Sbill * Free all the disk blocks associated 33024Sbill * with the specified inode structure. 33124Sbill * The blocks of the file are removed 33224Sbill * in reverse order. This FILO 33324Sbill * algorithm will tend to maintain 33424Sbill * a contiguous free list much longer 33524Sbill * than FIFO. 33624Sbill */ 33724Sbill itrunc(ip) 3384818Swnj register struct inode *ip; 33924Sbill { 34024Sbill register i; 34124Sbill dev_t dev; 34224Sbill daddr_t bn; 3431203Sbill struct inode itmp; 3446569Smckusic register struct fs *fs; 3457492Skre #ifdef QUOTA 3467492Skre register long cnt = 0; 3477492Skre long tloop(); 3487492Skre #endif 34924Sbill 3501203Sbill /* 3511203Sbill * Clean inode on disk before freeing blocks 3521203Sbill * to insure no duplicates if system crashes. 3531203Sbill */ 3541203Sbill itmp = *ip; 3551203Sbill itmp.i_size = 0; 3566569Smckusic for (i = 0; i < NDADDR; i++) 3576569Smckusic itmp.i_db[i] = 0; 3586569Smckusic for (i = 0; i < NIADDR; i++) 3596569Smckusic itmp.i_ib[i] = 0; 3601203Sbill itmp.i_flag |= ICHG|IUPD; 3611203Sbill iupdat(&itmp, &time, &time, 1); 3621203Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 3631203Sbill 3641203Sbill /* 3657341Sroot * Only plain files, directories and symbolic 3667341Sroot * links contain blocks. 3677341Sroot */ 3687341Sroot i = ip->i_mode & IFMT; 3697341Sroot if (i != IFREG && i != IFDIR && i != IFLNK) 3707341Sroot return; 3717341Sroot /* 3721203Sbill * Now return blocks to free list... if machine 3731203Sbill * crashes, they will be harmless MISSING blocks. 3741203Sbill */ 37524Sbill dev = ip->i_dev; 3766569Smckusic fs = ip->i_fs; 3776569Smckusic /* 3786569Smckusic * release double indirect block first 3796569Smckusic */ 3806569Smckusic bn = ip->i_ib[NIADDR-1]; 3816569Smckusic if (bn != (daddr_t)0) { 3826569Smckusic ip->i_ib[NIADDR - 1] = (daddr_t)0; 3837492Skre #ifdef QUOTA 3847492Skre cnt += 3857492Skre #endif 3867492Skre tloop(ip, bn, 1); 3876569Smckusic } 3886569Smckusic /* 3896569Smckusic * release single indirect blocks second 3906569Smckusic */ 3916569Smckusic for (i = NIADDR - 2; i >= 0; i--) { 3926569Smckusic bn = ip->i_ib[i]; 3936569Smckusic if (bn != (daddr_t)0) { 3946569Smckusic ip->i_ib[i] = (daddr_t)0; 3957492Skre #ifdef QUOTA 3967492Skre cnt += 3977492Skre #endif 3987492Skre tloop(ip, bn, 0); 3996569Smckusic } 4006569Smckusic } 4016569Smckusic /* 4026569Smckusic * finally release direct blocks 4036569Smckusic */ 4046569Smckusic for (i = NDADDR - 1; i>=0; i--) { 4057492Skre register size; 4067492Skre 4076569Smckusic bn = ip->i_db[i]; 4084818Swnj if (bn == (daddr_t)0) 40924Sbill continue; 4106569Smckusic ip->i_db[i] = (daddr_t)0; 4117492Skre fre(ip, bn, size = (off_t)blksize(fs, ip, i)); 4127492Skre #ifdef QUOTA 4137492Skre cnt += size / DEV_BSIZE; 4147492Skre #endif 41524Sbill } 41624Sbill ip->i_size = 0; 4171203Sbill /* 4181203Sbill * Inode was written and flags updated above. 4191203Sbill * No need to modify flags here. 4201203Sbill */ 4217492Skre #ifdef QUOTA 4227492Skre (void) chkdq(ip, -cnt, 0); 4237492Skre #endif 42424Sbill } 42524Sbill 4267492Skre #ifdef QUOTA 4277492Skre long 4287492Skre #endif 4296569Smckusic tloop(ip, bn, indflg) 4306569Smckusic register struct inode *ip; 4316569Smckusic daddr_t bn; 4326569Smckusic int indflg; 43324Sbill { 43424Sbill register i; 43524Sbill register struct buf *bp; 43624Sbill register daddr_t *bap; 4376569Smckusic register struct fs *fs; 43824Sbill daddr_t nb; 4397492Skre #ifdef QUOTA 4407492Skre register long cnt = 0; 4417492Skre #endif 44224Sbill 44324Sbill bp = NULL; 4446569Smckusic fs = ip->i_fs; 4456569Smckusic for (i = NINDIR(fs) - 1; i >= 0; i--) { 4464818Swnj if (bp == NULL) { 4476569Smckusic bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize); 44824Sbill if (bp->b_flags & B_ERROR) { 44924Sbill brelse(bp); 45024Sbill return; 45124Sbill } 45224Sbill bap = bp->b_un.b_daddr; 45324Sbill } 45424Sbill nb = bap[i]; 4554818Swnj if (nb == (daddr_t)0) 45624Sbill continue; 4577492Skre if (indflg) { 4587492Skre #ifdef QUOTA 4597492Skre cnt += 4607492Skre #endif 4617492Skre tloop(ip, nb, 0); 4627492Skre } else { 4636569Smckusic fre(ip, nb, fs->fs_bsize); 4647492Skre #ifdef QUOTA 4657492Skre cnt += fs->fs_bsize / DEV_BSIZE; 4667492Skre #endif 4677492Skre } 46824Sbill } 4694818Swnj if (bp != NULL) 47024Sbill brelse(bp); 4716569Smckusic fre(ip, bn, fs->fs_bsize); 4727492Skre #ifdef QUOTA 4737492Skre cnt += fs->fs_bsize / DEV_BSIZE; 4747492Skre return(cnt); 4757492Skre #endif 47624Sbill } 47724Sbill 47824Sbill /* 47924Sbill * Make a new file. 48024Sbill */ 48124Sbill struct inode * 48224Sbill maknode(mode) 4836569Smckusic int mode; 48424Sbill { 48524Sbill register struct inode *ip; 4866569Smckusic ino_t ipref; 48724Sbill 4886569Smckusic if ((mode & IFMT) == IFDIR) 4896569Smckusic ipref = dirpref(u.u_pdir->i_fs); 4906569Smckusic else 4916569Smckusic ipref = u.u_pdir->i_number; 4926569Smckusic ip = ialloc(u.u_pdir, ipref, mode); 4934818Swnj if (ip == NULL) { 49424Sbill iput(u.u_pdir); 49524Sbill return(NULL); 49624Sbill } 4977492Skre #ifdef QUOTA 4987492Skre if (ip->i_dquot != NODQUOT) 4997492Skre panic("maknode: dquot"); 5007492Skre #endif 50124Sbill ip->i_flag |= IACC|IUPD|ICHG; 5026569Smckusic if ((mode & IFMT) == 0) 50324Sbill mode |= IFREG; 50424Sbill ip->i_mode = mode & ~u.u_cmask; 50524Sbill ip->i_nlink = 1; 50624Sbill ip->i_uid = u.u_uid; 5075855Swnj ip->i_gid = u.u_pdir->i_gid; 5087492Skre #ifdef QUOTA 5097492Skre ip->i_dquot = inoquota(ip); 5107492Skre #endif 5111203Sbill 5121203Sbill /* 5131203Sbill * Make sure inode goes to disk before directory entry. 5141203Sbill */ 5151203Sbill iupdat(ip, &time, &time, 1); 51624Sbill wdir(ip); 5176569Smckusic if (u.u_error) { 5186569Smckusic /* 5196569Smckusic * write error occurred trying to update directory 5206569Smckusic * so must deallocate the inode 5216569Smckusic */ 5226569Smckusic ip->i_nlink = 0; 5236569Smckusic ip->i_flag |= ICHG; 5246569Smckusic iput(ip); 5256569Smckusic return(NULL); 5266569Smckusic } 52724Sbill return(ip); 52824Sbill } 52924Sbill 53024Sbill /* 53124Sbill * Write a directory entry with 53224Sbill * parameters left as side effects 53324Sbill * to a call to namei. 53424Sbill */ 53524Sbill wdir(ip) 5364818Swnj struct inode *ip; 53724Sbill { 5386569Smckusic register struct direct *dp, *ndp; 5396569Smckusic struct fs *fs; 5406569Smckusic struct buf *bp; 5416569Smckusic int lbn, bn, base; 5426569Smckusic int loc, dsize, spccnt, newsize; 5436569Smckusic char *dirbuf; 54424Sbill 54524Sbill u.u_dent.d_ino = ip->i_number; 54624Sbill u.u_segflg = 1; 5476569Smckusic newsize = DIRSIZ(&u.u_dent); 5486569Smckusic /* 5496569Smckusic * if u.u_count == 0, a new directory block must be allocated. 5506569Smckusic */ 5516569Smckusic if (u.u_count == 0) { 5526569Smckusic u.u_dent.d_reclen = DIRBLKSIZ; 5536569Smckusic u.u_count = newsize; 5546569Smckusic u.u_base = (caddr_t)&u.u_dent; 555*7504Sroot /*ZZ*/if((u.u_offset&0x1ff))panic("wdir: newblk"); 5566569Smckusic writei(u.u_pdir); 5576569Smckusic iput(u.u_pdir); 5586569Smckusic return; 5596569Smckusic } 5606569Smckusic /* 5616569Smckusic * must read in an existing directory block 5626569Smckusic * to prepare to place the new entry into it. 5636569Smckusic */ 5646569Smckusic fs = u.u_pdir->i_fs; 5656569Smckusic lbn = lblkno(fs, u.u_offset); 5666569Smckusic base = blkoff(fs, u.u_offset); 5676569Smckusic bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count)); 5686569Smckusic if (u.u_offset + u.u_count > u.u_pdir->i_size) 569*7504Sroot /*ZZ*/{if((u.u_offset+u.u_count-1&~0x1ff)!=(u.u_pdir->i_size-1&~0x1ff)) 570*7504Sroot /*ZZ*/ printf("wdir i_size dir %s/%d (of=%d,cnt=%d,psz=%d))\n", 571*7504Sroot /*ZZ*/ u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number,u.u_offset, 572*7504Sroot /*ZZ*/ u.u_count,u.u_pdir->i_size); 5736569Smckusic u.u_pdir->i_size = u.u_offset + u.u_count; 574*7504Sroot /*ZZ*/} 5756569Smckusic bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn)); 5766569Smckusic if (bp->b_flags & B_ERROR) { 5776569Smckusic brelse(bp); 5786569Smckusic return; 5796569Smckusic } 5806569Smckusic dirbuf = bp->b_un.b_addr + base; 5816569Smckusic dp = (struct direct *)dirbuf; 5826569Smckusic dsize = DIRSIZ(dp); 5836569Smckusic spccnt = dp->d_reclen - dsize; 5846569Smckusic /* 5856569Smckusic * if there is insufficient room to make an entry at this point 5866569Smckusic * namei insures that compacting from u.u_offset for u.u_count 5876569Smckusic * bytes will provide the necessary space. 5886569Smckusic */ 5896569Smckusic for (loc = dp->d_reclen; loc < u.u_count; ) { 5906569Smckusic ndp = (struct direct *)(dirbuf + loc); 5916569Smckusic if (dp->d_ino == 0) { 5926569Smckusic spccnt += dsize; 5936569Smckusic } else { 5946569Smckusic dp->d_reclen = dsize; 5956569Smckusic dp = (struct direct *)((char *)dp + dsize); 5966569Smckusic } 5976569Smckusic dsize = DIRSIZ(ndp); 5986569Smckusic spccnt += ndp->d_reclen - dsize; 599*7504Sroot /*ZZ*/if(spccnt>512)panic("wdir spccnt"); 600*7504Sroot /*ZZ*/if((loc&~0x1ff)!=(loc+ndp->d_reclen-1&~0x1ff)) 601*7504Sroot /*ZZ*/printf("wdir: compact loc %d reclen %d (dir %s/%d)\n",loc,ndp->d_reclen, 602*7504Sroot /*ZZ*/u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number); 6036569Smckusic loc += ndp->d_reclen; 6046569Smckusic bcopy(ndp, dp, dsize); 6056569Smckusic } 6066569Smckusic /* 6076569Smckusic * Update the pointer fields in the previous entry (if any), 6086569Smckusic * copy in the new entry, and write out the block. 6096569Smckusic */ 6106569Smckusic if (dp->d_ino == 0) { 6116569Smckusic if (spccnt + dsize < newsize) 612*7504Sroot panic("wdir: compact failed (1)"); 613*7504Sroot /*ZZ*/if(spccnt+dsize>512)panic("wdir: compact screwup"); 6146569Smckusic u.u_dent.d_reclen = spccnt + dsize; 6156569Smckusic } else { 6166569Smckusic if (spccnt < newsize) 617*7504Sroot panic("wdir: compact failed (2)"); 6186569Smckusic u.u_dent.d_reclen = spccnt; 619*7504Sroot /*ZZ*/if ((((char *)dp-bp->b_un.b_addr)&0x1ff)+dsize>512) panic("wdir: reclen"); 6206569Smckusic dp->d_reclen = dsize; 6216569Smckusic dp = (struct direct *)((char *)dp + dsize); 6226569Smckusic } 623*7504Sroot /*ZZ*/if((((char*)dp-bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen>512)panic("wdir: botch"); 6246569Smckusic bcopy(&u.u_dent, dp, newsize); 6256569Smckusic bwrite(bp); 6266569Smckusic u.u_pdir->i_flag |= IUPD|ICHG; 62724Sbill iput(u.u_pdir); 62824Sbill } 6293617Sroot 6307334Skre /* 6317334Skre * remove any inodes in the inode cache belonging to dev 6327334Skre * 6337334Skre * There should not be any active ones, return error if any are found 6347334Skre * (nb: this is a user error, not a system err) 6357334Skre * 6367334Skre * Also, count the references to dev by block devices - this really 6377334Skre * has nothing to do with the object of the procedure, but as we have 6387334Skre * to scan the inode table here anyway, we might as well get the 6397334Skre * extra benefit. 6407334Skre * 6417334Skre * this is called from sumount()/sys3.c when dev is being unmounted 6427334Skre */ 6437492Skre #ifdef QUOTA 644*7504Sroot iflush(dev, iq) 6457492Skre dev_t dev; 646*7504Sroot struct inode *iq; 6477492Skre #else 6487334Skre iflush(dev) 6497334Skre dev_t dev; 6507492Skre #endif 6517334Skre { 6527335Skre register struct inode *ip; 6537334Skre register open = 0; 6547334Skre 6557334Skre for (ip = inode; ip < inodeNINODE; ip++) { 6567492Skre #ifdef QUOTA 6577492Skre if (ip != iq && ip->i_dev == dev) 6587492Skre #else 6597334Skre if (ip->i_dev == dev) 6607492Skre #endif 6617334Skre if (ip->i_count) 6627334Skre return(-1); 6637334Skre else { 6647335Skre remque(ip); 6657334Skre ip->i_forw = ip; 6667334Skre ip->i_back = ip; 6677334Skre /* 6687334Skre * as i_count == 0, the inode was on the free 6697334Skre * list already, just leave it there, it will 6707334Skre * fall off the bottom eventually. We could 6717334Skre * perhaps move it to the head of the free 6727334Skre * list, but as umounts are done so 6737334Skre * infrequently, we would gain very little, 6747334Skre * while making the code bigger. 6757334Skre */ 6767492Skre #ifdef QUOTA 6777492Skre dqrele(ip->i_dquot); 6787492Skre ip->i_dquot = NODQUOT; 6797492Skre #endif 6807334Skre } 6817334Skre else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && 6827334Skre ip->i_rdev == dev) 6837334Skre open++; 6847334Skre } 6857334Skre return (open); 6867334Skre } 6877334Skre 6884818Swnj #ifdef ilock 6894818Swnj #undef ilock 6903617Sroot #endif 6917118Smckusick #ifdef iunlock 6927118Smckusick #undef iunlock 6933617Sroot #endif 6943617Sroot /* 6954818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6963617Sroot */ 6974818Swnj ilock(ip) 6984818Swnj register struct inode *ip; 6993617Sroot { 7003617Sroot 7014818Swnj while (ip->i_flag&ILOCK) { 7023617Sroot ip->i_flag |= IWANT; 7033617Sroot sleep((caddr_t)ip, PINOD); 7043617Sroot } 7053617Sroot ip->i_flag |= ILOCK; 7063617Sroot } 7073617Sroot 7083617Sroot /* 7094818Swnj * Unlock an inode. If WANT bit is on, wakeup. 7103617Sroot */ 7117118Smckusick iunlock(ip) 7124818Swnj register struct inode *ip; 7133617Sroot { 7143617Sroot 7153617Sroot ip->i_flag &= ~ILOCK; 7164818Swnj if (ip->i_flag&IWANT) { 7173617Sroot ip->i_flag &= ~IWANT; 7183617Sroot wakeup((caddr_t)ip); 7193617Sroot } 7203617Sroot } 721