1*7334Skre /* lfs_inode.c 4.13 82/06/29 */ 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" 1324Sbill 1424Sbill #define INOHSZ 63 15*7334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 16*7334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 17*7334Skre #else 1824Sbill #define INOHASH(dev,ino) (((dev)+(ino))%INOHSZ) 19*7334Skre #endif 2024Sbill 21*7334Skre union ihead { /* inode LRU cache, Chris Maltby */ 22*7334Skre union ihead *ih_head[2]; 23*7334Skre struct inode *ih_chain[2]; 24*7334Skre } ihead[INOHSZ]; 25*7334Skre 26*7334Skre struct inode *ifreeh, **ifreet; 27*7334Skre 2824Sbill /* 2924Sbill * Initialize hash links for inodes 3024Sbill * and build inode free list. 3124Sbill */ 3224Sbill ihinit() 3324Sbill { 3424Sbill register int i; 352737Swnj register struct inode *ip = inode; 36*7334Skre register union ihead *ih = ihead; 3724Sbill 38*7334Skre for (i = INOHSZ; --i >= 0; ih++) { 39*7334Skre ih->ih_head[0] = ih; 40*7334Skre ih->ih_head[1] = ih; 41*7334Skre } 42*7334Skre ifreeh = ip; 43*7334Skre ifreet = &ip->i_freef; 44*7334Skre ip->i_freeb = &ifreeh; 45*7334Skre ip->i_forw = ip; 46*7334Skre ip->i_back = ip; 47*7334Skre for (i = ninode; --i > 0; ) { 48*7334Skre ++ip; 49*7334Skre ip->i_forw = ip; 50*7334Skre ip->i_back = ip; 51*7334Skre *ifreet = ip; 52*7334Skre ip->i_freeb = ifreet; 53*7334Skre ifreet = &ip->i_freef; 54*7334Skre } 55*7334Skre ip->i_freef = NULL; 5624Sbill } 5724Sbill 58*7334Skre #ifdef notdef 5924Sbill /* 60*7334Skre * Find an inode if it is incore. 61*7334Skre * This is the equivalent, for inodes, 62*7334Skre * of ``incore'' in bio.c or ``pfind'' in subr.c. 63*7334Skre */ 64*7334Skre struct inode * 65*7334Skre ifind(dev, ino) 66*7334Skre dev_t dev; 67*7334Skre ino_t ino; 68*7334Skre { 69*7334Skre register struct inode *ip; 70*7334Skre register union ihead *ih; 71*7334Skre 72*7334Skre ih = &ihead[INOHASH(dev, ino)]; 73*7334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 74*7334Skre if (ino==ip->i_number && dev==ip->i_dev) 75*7334Skre return (ip); 76*7334Skre return ((struct inode *)0); 77*7334Skre } 78*7334Skre #endif notdef 79*7334Skre 80*7334Skre /* 8124Sbill * Look up an inode by device,inumber. 8224Sbill * If it is in core (in the inode structure), 8324Sbill * honor the locking protocol. 8424Sbill * If it is not in core, read it in from the 8524Sbill * specified device. 8624Sbill * If the inode is mounted on, perform 8724Sbill * the indicated indirection. 8824Sbill * In all cases, a pointer to a locked 8924Sbill * inode structure is returned. 9024Sbill * 9124Sbill * panic: no imt -- if the mounted file 9224Sbill * system is not in the mount table. 9324Sbill * "cannot happen" 9424Sbill */ 9524Sbill struct inode * 966569Smckusic iget(dev, fs, ino) 974818Swnj dev_t dev; 986569Smckusic register struct fs *fs; 994818Swnj ino_t ino; 10024Sbill { 101*7334Skre register struct inode *ip; /* known to be r11 - see "asm" below */ 102*7334Skre register union ihead *ih; /* known to be r10 - see "asm" below */ 10324Sbill register struct mount *mp; 10424Sbill register struct buf *bp; 10524Sbill register struct dinode *dp; 106*7334Skre register struct inode *iq; 10724Sbill 10824Sbill loop: 1096569Smckusic if (getfs(dev) != fs) 1106569Smckusic panic("iget: bad fs"); 111*7334Skre ih = &ihead[INOHASH(dev, ino)]; 112*7334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 1134818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 1144818Swnj if ((ip->i_flag&ILOCK) != 0) { 11524Sbill ip->i_flag |= IWANT; 11624Sbill sleep((caddr_t)ip, PINOD); 11724Sbill goto loop; 11824Sbill } 1194818Swnj if ((ip->i_flag&IMOUNT) != 0) { 1206569Smckusic for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 121*7334Skre if(mp->m_inodp == ip) { 122*7334Skre dev = mp->m_dev; 123*7334Skre fs = mp->m_bufp->b_un.b_fs; 124*7334Skre ino = ROOTINO; 125*7334Skre goto loop; 126*7334Skre } 12724Sbill panic("no imt"); 12824Sbill } 129*7334Skre if (ip->i_count == 0) { /* ino on free list */ 130*7334Skre if (iq = ip->i_freef) 131*7334Skre iq->i_freeb = ip->i_freeb; 132*7334Skre else 133*7334Skre ifreet = ip->i_freeb; 134*7334Skre *ip->i_freeb = iq; 135*7334Skre ip->i_freef = NULL; 136*7334Skre ip->i_freeb = NULL; 137*7334Skre } 13824Sbill ip->i_count++; 13924Sbill ip->i_flag |= ILOCK; 14024Sbill return(ip); 14124Sbill } 142*7334Skre 143*7334Skre if ((ip = ifreeh) == NULL) { 1442933Swnj tablefull("inode"); 14524Sbill u.u_error = ENFILE; 14624Sbill return(NULL); 14724Sbill } 148*7334Skre if (iq = ip->i_freef) 149*7334Skre iq->i_freeb = &ifreeh; 150*7334Skre ifreeh = iq; 151*7334Skre ip->i_freef = NULL; 152*7334Skre ip->i_freeb = NULL; 153*7334Skre /* 154*7334Skre * Now to take inode off the hash chain it was on 155*7334Skre * (initially, or after an iflush, it is on a "hash chain" 156*7334Skre * consisting entirely of itself, and pointed to by no-one, 157*7334Skre * but that doesn't matter), and put it on the chain for 158*7334Skre * its new (ino, dev) pair 159*7334Skre */ 160*7334Skre #ifndef UNFAST 161*7334Skre asm("remque (r11),r0"); 162*7334Skre asm("insque (r11),(r10)"); 163*7334Skre #else 164*7334Skre /* remque */ 165*7334Skre ip->i_back->i_forw = ip->i_forw; 166*7334Skre ip->i_forw->i_back = ip->i_back; 167*7334Skre /* insque */ 168*7334Skre ip->i_forw = ih->ih_chain[0]; 169*7334Skre ip->i_back = (struct inode *)ih; 170*7334Skre ih->ih_chain[0]->i_back = ip; 171*7334Skre ih->ih_chain[0] = ip; 172*7334Skre #endif 17324Sbill ip->i_dev = dev; 1746569Smckusic ip->i_fs = fs; 17524Sbill ip->i_number = ino; 17624Sbill ip->i_flag = ILOCK; 17724Sbill ip->i_count++; 1786569Smckusic ip->i_lastr = 0; 1796569Smckusic bp = bread(dev, fsbtodb(fs, itod(fs, ino)), fs->fs_bsize); 18024Sbill /* 18124Sbill * Check I/O errors 18224Sbill */ 1834818Swnj if ((bp->b_flags&B_ERROR) != 0) { 18424Sbill brelse(bp); 185*7334Skre /* 186*7334Skre * the inode doesn't contain anything useful, so it would 187*7334Skre * be misleading to leave it on its hash chain. 188*7334Skre * 'iput' will take care of putting it back on the free list. 189*7334Skre */ 190*7334Skre #ifndef UNFAST 191*7334Skre asm("remque (r11),r0"); 192*7334Skre #else 193*7334Skre ip->i_back->i_forw = ip->i_forw; 194*7334Skre ip->i_forw->i_back = ip->i_back; 195*7334Skre #endif 196*7334Skre ip->i_forw = ip; 197*7334Skre ip->i_back = ip; 198*7334Skre /* 199*7334Skre * we also loose its inumber, just in case (as iput 200*7334Skre * doesn't do that any more) - but as it isn't on its 201*7334Skre * hash chain, I doubt if this is really necessary .. kre 202*7334Skre * (probably the two methods are interchangable) 203*7334Skre */ 204*7334Skre ip->i_number = 0; 20524Sbill iput(ip); 20624Sbill return(NULL); 20724Sbill } 20824Sbill dp = bp->b_un.b_dino; 2096569Smckusic dp += itoo(fs, ino); 2106569Smckusic ip->i_ic = dp->di_ic; 21124Sbill brelse(bp); 2126569Smckusic return (ip); 21324Sbill } 21424Sbill 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"); 2287118Smckusick iunlock(ip); 2297118Smckusick irele(ip); 2307118Smckusick } 2317118Smckusick 2327118Smckusick irele(ip) 2337118Smckusick register struct inode *ip; 2347118Smckusick { 23524Sbill register int i, x; 23624Sbill register struct inode *jp; 2376569Smckusic int mode; 23824Sbill 2394818Swnj if (ip->i_count == 1) { 24024Sbill ip->i_flag |= ILOCK; 2414818Swnj if (ip->i_nlink <= 0) { 24224Sbill itrunc(ip); 2436569Smckusic mode = ip->i_mode; 24424Sbill ip->i_mode = 0; 24524Sbill ip->i_flag |= IUPD|ICHG; 2466569Smckusic ifree(ip, ip->i_number, mode); 24724Sbill } 2481203Sbill IUPDAT(ip, &time, &time, 0); 2497118Smckusick iunlock(ip); 250*7334Skre ip->i_flag = 0; 251*7334Skre /* 252*7334Skre * Put the inode on the end of the free list. 253*7334Skre * Possibly in some cases it would be better to 254*7334Skre * put the inode at the head of the free list, 255*7334Skre * (eg: where i_mode == 0 || i_number == 0) 256*7334Skre * but I will think about that later .. kre 257*7334Skre * (i_number is rarely 0 - only after an i/o error in iget, 258*7334Skre * where i_mode == 0, the inode will probably be wanted 259*7334Skre * again soon for an ialloc, so possibly we should keep it) 260*7334Skre */ 261*7334Skre if (ifreeh) { 262*7334Skre *ifreet = ip; 263*7334Skre ip->i_freeb = ifreet; 26424Sbill } else { 265*7334Skre ifreeh = ip; 266*7334Skre ip->i_freeb = &ifreeh; 26724Sbill } 268*7334Skre ip->i_freef = NULL; 269*7334Skre ifreet = &ip->i_freef; 2707118Smckusick } 27124Sbill ip->i_count--; 27224Sbill } 27324Sbill 27424Sbill /* 27524Sbill * Check accessed and update flags on 27624Sbill * an inode structure. 27724Sbill * If any is on, update the inode 27824Sbill * with the current time. 2791203Sbill * If waitfor is given, then must insure 2801203Sbill * i/o order so wait for write to complete. 28124Sbill */ 2821203Sbill iupdat(ip, ta, tm, waitfor) 2834818Swnj register struct inode *ip; 2844818Swnj time_t *ta, *tm; 2854818Swnj int waitfor; 28624Sbill { 28724Sbill register struct buf *bp; 28824Sbill struct dinode *dp; 2896569Smckusic register struct fs *fp; 29024Sbill 2916569Smckusic fp = ip->i_fs; 2926569Smckusic if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) { 2936569Smckusic if (fp->fs_ronly) 29424Sbill return; 2956569Smckusic bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 2966569Smckusic fp->fs_bsize); 29724Sbill if (bp->b_flags & B_ERROR) { 29824Sbill brelse(bp); 29924Sbill return; 30024Sbill } 3014818Swnj if (ip->i_flag&IACC) 3026569Smckusic ip->i_atime = *ta; 3034818Swnj if (ip->i_flag&IUPD) 3046569Smckusic ip->i_mtime = *tm; 3054818Swnj if (ip->i_flag&ICHG) 3066569Smckusic ip->i_ctime = time; 30724Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 3081203Sbill if (waitfor) 3091203Sbill bwrite(bp); 3101203Sbill else 3111203Sbill bdwrite(bp); 31224Sbill } 31324Sbill } 31424Sbill 31524Sbill /* 31624Sbill * Free all the disk blocks associated 31724Sbill * with the specified inode structure. 31824Sbill * The blocks of the file are removed 31924Sbill * in reverse order. This FILO 32024Sbill * algorithm will tend to maintain 32124Sbill * a contiguous free list much longer 32224Sbill * than FIFO. 32324Sbill */ 32424Sbill itrunc(ip) 3254818Swnj register struct inode *ip; 32624Sbill { 32724Sbill register i; 32824Sbill dev_t dev; 32924Sbill daddr_t bn; 3301203Sbill struct inode itmp; 3316569Smckusic register struct fs *fs; 33224Sbill 33324Sbill i = ip->i_mode & IFMT; 3346569Smckusic if (i != IFREG && i != IFDIR && i != IFLNK) 33524Sbill return; 3361203Sbill /* 3371203Sbill * Clean inode on disk before freeing blocks 3381203Sbill * to insure no duplicates if system crashes. 3391203Sbill */ 3401203Sbill itmp = *ip; 3411203Sbill itmp.i_size = 0; 3426569Smckusic for (i = 0; i < NDADDR; i++) 3436569Smckusic itmp.i_db[i] = 0; 3446569Smckusic for (i = 0; i < NIADDR; i++) 3456569Smckusic itmp.i_ib[i] = 0; 3461203Sbill itmp.i_flag |= ICHG|IUPD; 3471203Sbill iupdat(&itmp, &time, &time, 1); 3481203Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 3491203Sbill 3501203Sbill /* 3511203Sbill * Now return blocks to free list... if machine 3521203Sbill * crashes, they will be harmless MISSING blocks. 3531203Sbill */ 35424Sbill dev = ip->i_dev; 3556569Smckusic fs = ip->i_fs; 3566569Smckusic /* 3576569Smckusic * release double indirect block first 3586569Smckusic */ 3596569Smckusic bn = ip->i_ib[NIADDR-1]; 3606569Smckusic if (bn != (daddr_t)0) { 3616569Smckusic ip->i_ib[NIADDR - 1] = (daddr_t)0; 3626569Smckusic tloop(ip, bn, 1); 3636569Smckusic } 3646569Smckusic /* 3656569Smckusic * release single indirect blocks second 3666569Smckusic */ 3676569Smckusic for (i = NIADDR - 2; i >= 0; i--) { 3686569Smckusic bn = ip->i_ib[i]; 3696569Smckusic if (bn != (daddr_t)0) { 3706569Smckusic ip->i_ib[i] = (daddr_t)0; 3716569Smckusic tloop(ip, bn, 0); 3726569Smckusic } 3736569Smckusic } 3746569Smckusic /* 3756569Smckusic * finally release direct blocks 3766569Smckusic */ 3776569Smckusic for (i = NDADDR - 1; i>=0; i--) { 3786569Smckusic bn = ip->i_db[i]; 3794818Swnj if (bn == (daddr_t)0) 38024Sbill continue; 3816569Smckusic ip->i_db[i] = (daddr_t)0; 3826569Smckusic fre(ip, bn, (off_t)blksize(fs, ip, i)); 38324Sbill } 38424Sbill ip->i_size = 0; 3851203Sbill /* 3861203Sbill * Inode was written and flags updated above. 3871203Sbill * No need to modify flags here. 3881203Sbill */ 38924Sbill } 39024Sbill 3916569Smckusic tloop(ip, bn, indflg) 3926569Smckusic register struct inode *ip; 3936569Smckusic daddr_t bn; 3946569Smckusic int indflg; 39524Sbill { 39624Sbill register i; 39724Sbill register struct buf *bp; 39824Sbill register daddr_t *bap; 3996569Smckusic register struct fs *fs; 40024Sbill daddr_t nb; 40124Sbill 40224Sbill bp = NULL; 4036569Smckusic fs = ip->i_fs; 4046569Smckusic for (i = NINDIR(fs) - 1; i >= 0; i--) { 4054818Swnj if (bp == NULL) { 4066569Smckusic bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize); 40724Sbill if (bp->b_flags & B_ERROR) { 40824Sbill brelse(bp); 40924Sbill return; 41024Sbill } 41124Sbill bap = bp->b_un.b_daddr; 41224Sbill } 41324Sbill nb = bap[i]; 4144818Swnj if (nb == (daddr_t)0) 41524Sbill continue; 4166569Smckusic if (indflg) 4176569Smckusic tloop(ip, nb, 0); 4186569Smckusic else 4196569Smckusic fre(ip, nb, fs->fs_bsize); 42024Sbill } 4214818Swnj if (bp != NULL) 42224Sbill brelse(bp); 4236569Smckusic fre(ip, bn, fs->fs_bsize); 42424Sbill } 42524Sbill 42624Sbill /* 42724Sbill * Make a new file. 42824Sbill */ 42924Sbill struct inode * 43024Sbill maknode(mode) 4316569Smckusic int mode; 43224Sbill { 43324Sbill register struct inode *ip; 4346569Smckusic ino_t ipref; 43524Sbill 4366569Smckusic if ((mode & IFMT) == IFDIR) 4376569Smckusic ipref = dirpref(u.u_pdir->i_fs); 4386569Smckusic else 4396569Smckusic ipref = u.u_pdir->i_number; 4406569Smckusic ip = ialloc(u.u_pdir, ipref, mode); 4414818Swnj if (ip == NULL) { 44224Sbill iput(u.u_pdir); 44324Sbill return(NULL); 44424Sbill } 44524Sbill ip->i_flag |= IACC|IUPD|ICHG; 4466569Smckusic if ((mode & IFMT) == 0) 44724Sbill mode |= IFREG; 44824Sbill ip->i_mode = mode & ~u.u_cmask; 44924Sbill ip->i_nlink = 1; 45024Sbill ip->i_uid = u.u_uid; 4515855Swnj ip->i_gid = u.u_pdir->i_gid; 4521203Sbill 4531203Sbill /* 4541203Sbill * Make sure inode goes to disk before directory entry. 4551203Sbill */ 4561203Sbill iupdat(ip, &time, &time, 1); 45724Sbill wdir(ip); 4586569Smckusic if (u.u_error) { 4596569Smckusic /* 4606569Smckusic * write error occurred trying to update directory 4616569Smckusic * so must deallocate the inode 4626569Smckusic */ 4636569Smckusic ip->i_nlink = 0; 4646569Smckusic ip->i_flag |= ICHG; 4656569Smckusic iput(ip); 4666569Smckusic return(NULL); 4676569Smckusic } 46824Sbill return(ip); 46924Sbill } 47024Sbill 47124Sbill /* 47224Sbill * Write a directory entry with 47324Sbill * parameters left as side effects 47424Sbill * to a call to namei. 47524Sbill */ 47624Sbill wdir(ip) 4774818Swnj struct inode *ip; 47824Sbill { 4796569Smckusic register struct direct *dp, *ndp; 4806569Smckusic struct fs *fs; 4816569Smckusic struct buf *bp; 4826569Smckusic int lbn, bn, base; 4836569Smckusic int loc, dsize, spccnt, newsize; 4846569Smckusic char *dirbuf; 48524Sbill 48624Sbill u.u_dent.d_ino = ip->i_number; 48724Sbill u.u_segflg = 1; 4886569Smckusic newsize = DIRSIZ(&u.u_dent); 4896569Smckusic /* 4906569Smckusic * if u.u_count == 0, a new directory block must be allocated. 4916569Smckusic */ 4926569Smckusic if (u.u_count == 0) { 4936569Smckusic u.u_dent.d_reclen = DIRBLKSIZ; 4946569Smckusic u.u_count = newsize; 4956569Smckusic u.u_base = (caddr_t)&u.u_dent; 4966569Smckusic writei(u.u_pdir); 4976569Smckusic iput(u.u_pdir); 4986569Smckusic return; 4996569Smckusic } 5006569Smckusic /* 5016569Smckusic * must read in an existing directory block 5026569Smckusic * to prepare to place the new entry into it. 5036569Smckusic */ 5046569Smckusic fs = u.u_pdir->i_fs; 5056569Smckusic lbn = lblkno(fs, u.u_offset); 5066569Smckusic base = blkoff(fs, u.u_offset); 5076569Smckusic bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count)); 5086569Smckusic if (u.u_offset + u.u_count > u.u_pdir->i_size) 5096569Smckusic u.u_pdir->i_size = u.u_offset + u.u_count; 5106569Smckusic bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn)); 5116569Smckusic if (bp->b_flags & B_ERROR) { 5126569Smckusic brelse(bp); 5136569Smckusic return; 5146569Smckusic } 5156569Smckusic dirbuf = bp->b_un.b_addr + base; 5166569Smckusic dp = (struct direct *)dirbuf; 5176569Smckusic dsize = DIRSIZ(dp); 5186569Smckusic spccnt = dp->d_reclen - dsize; 5196569Smckusic /* 5206569Smckusic * if there is insufficient room to make an entry at this point 5216569Smckusic * namei insures that compacting from u.u_offset for u.u_count 5226569Smckusic * bytes will provide the necessary space. 5236569Smckusic */ 5246569Smckusic for (loc = dp->d_reclen; loc < u.u_count; ) { 5256569Smckusic ndp = (struct direct *)(dirbuf + loc); 5266569Smckusic if (dp->d_ino == 0) { 5276569Smckusic spccnt += dsize; 5286569Smckusic } else { 5296569Smckusic dp->d_reclen = dsize; 5306569Smckusic dp = (struct direct *)((char *)dp + dsize); 5316569Smckusic } 5326569Smckusic dsize = DIRSIZ(ndp); 5336569Smckusic spccnt += ndp->d_reclen - dsize; 5346569Smckusic loc += ndp->d_reclen; 5356569Smckusic bcopy(ndp, dp, dsize); 5366569Smckusic } 5376569Smckusic /* 5386569Smckusic * Update the pointer fields in the previous entry (if any), 5396569Smckusic * copy in the new entry, and write out the block. 5406569Smckusic */ 5416569Smckusic if (dp->d_ino == 0) { 5426569Smckusic if (spccnt + dsize < newsize) 5436569Smckusic panic("wdir: compact failed"); 5446569Smckusic u.u_dent.d_reclen = spccnt + dsize; 5456569Smckusic } else { 5466569Smckusic if (spccnt < newsize) 5476569Smckusic panic("wdir: compact failed"); 5486569Smckusic u.u_dent.d_reclen = spccnt; 5496569Smckusic dp->d_reclen = dsize; 5506569Smckusic dp = (struct direct *)((char *)dp + dsize); 5516569Smckusic } 5526569Smckusic bcopy(&u.u_dent, dp, newsize); 5536569Smckusic bwrite(bp); 5546569Smckusic u.u_pdir->i_flag |= IUPD|ICHG; 55524Sbill iput(u.u_pdir); 55624Sbill } 5573617Sroot 558*7334Skre /* 559*7334Skre * remove any inodes in the inode cache belonging to dev 560*7334Skre * 561*7334Skre * There should not be any active ones, return error if any are found 562*7334Skre * (nb: this is a user error, not a system err) 563*7334Skre * 564*7334Skre * Also, count the references to dev by block devices - this really 565*7334Skre * has nothing to do with the object of the procedure, but as we have 566*7334Skre * to scan the inode table here anyway, we might as well get the 567*7334Skre * extra benefit. 568*7334Skre * 569*7334Skre * this is called from sumount()/sys3.c when dev is being unmounted 570*7334Skre */ 571*7334Skre iflush(dev) 572*7334Skre dev_t dev; 573*7334Skre { 574*7334Skre register struct inode *ip; /* known to be r11 - see 'asm' below */ 575*7334Skre register open = 0; 576*7334Skre 577*7334Skre for (ip = inode; ip < inodeNINODE; ip++) { 578*7334Skre if (ip->i_dev == dev) 579*7334Skre if (ip->i_count) 580*7334Skre return(-1); 581*7334Skre else { 582*7334Skre #ifndef UNFAST 583*7334Skre asm("remque (r11),r0"); 584*7334Skre #else 585*7334Skre ip->i_back->i_forw = ip->i_forw; 586*7334Skre ip->i_forw->i_back = ip->i_back; 587*7334Skre #endif 588*7334Skre ip->i_forw = ip; 589*7334Skre ip->i_back = ip; 590*7334Skre /* 591*7334Skre * as i_count == 0, the inode was on the free 592*7334Skre * list already, just leave it there, it will 593*7334Skre * fall off the bottom eventually. We could 594*7334Skre * perhaps move it to the head of the free 595*7334Skre * list, but as umounts are done so 596*7334Skre * infrequently, we would gain very little, 597*7334Skre * while making the code bigger. 598*7334Skre */ 599*7334Skre } 600*7334Skre else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && 601*7334Skre ip->i_rdev == dev) 602*7334Skre open++; 603*7334Skre } 604*7334Skre return (open); 605*7334Skre } 606*7334Skre 6074818Swnj #ifdef ilock 6084818Swnj #undef ilock 6093617Sroot #endif 6107118Smckusick #ifdef iunlock 6117118Smckusick #undef iunlock 6123617Sroot #endif 6133617Sroot /* 6144818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6153617Sroot */ 6164818Swnj ilock(ip) 6174818Swnj register struct inode *ip; 6183617Sroot { 6193617Sroot 6204818Swnj while (ip->i_flag&ILOCK) { 6213617Sroot ip->i_flag |= IWANT; 6223617Sroot sleep((caddr_t)ip, PINOD); 6233617Sroot } 6243617Sroot ip->i_flag |= ILOCK; 6253617Sroot } 6263617Sroot 6273617Sroot /* 6284818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6293617Sroot */ 6307118Smckusick iunlock(ip) 6314818Swnj register struct inode *ip; 6323617Sroot { 6333617Sroot 6343617Sroot ip->i_flag &= ~ILOCK; 6354818Swnj if (ip->i_flag&IWANT) { 6363617Sroot ip->i_flag &= ~IWANT; 6373617Sroot wakeup((caddr_t)ip); 6383617Sroot } 6393617Sroot } 640