1*7118Smckusick /* lfs_inode.c 4.11 82/06/07 */ 224Sbill 36569Smckusic /* merged into kernel: @(#)iget.c 2.2 4/8/82 */ 46569Smckusic 524Sbill #include "../h/param.h" 624Sbill #include "../h/systm.h" 724Sbill #include "../h/mount.h" 824Sbill #include "../h/dir.h" 924Sbill #include "../h/user.h" 1024Sbill #include "../h/inode.h" 116569Smckusic #include "../h/fs.h" 1224Sbill #include "../h/conf.h" 1324Sbill #include "../h/buf.h" 1424Sbill #include "../h/inline.h" 1524Sbill 1624Sbill #define INOHSZ 63 1724Sbill #define INOHASH(dev,ino) (((dev)+(ino))%INOHSZ) 1824Sbill short inohash[INOHSZ]; 1924Sbill short ifreel; 2024Sbill 2124Sbill /* 2224Sbill * Initialize hash links for inodes 2324Sbill * and build inode free list. 2424Sbill */ 2524Sbill ihinit() 2624Sbill { 2724Sbill register int i; 282737Swnj register struct inode *ip = inode; 2924Sbill 3024Sbill ifreel = 0; 312737Swnj for (i = 0; i < ninode-1; i++, ip++) 322737Swnj ip->i_hlink = i+1; 332737Swnj ip->i_hlink = -1; 3424Sbill for (i = 0; i < INOHSZ; i++) 3524Sbill inohash[i] = -1; 3624Sbill } 3724Sbill 3824Sbill /* 3924Sbill * Look up an inode by device,inumber. 4024Sbill * If it is in core (in the inode structure), 4124Sbill * honor the locking protocol. 4224Sbill * If it is not in core, read it in from the 4324Sbill * specified device. 4424Sbill * If the inode is mounted on, perform 4524Sbill * the indicated indirection. 4624Sbill * In all cases, a pointer to a locked 4724Sbill * inode structure is returned. 4824Sbill * 4924Sbill * panic: no imt -- if the mounted file 5024Sbill * system is not in the mount table. 5124Sbill * "cannot happen" 5224Sbill */ 5324Sbill struct inode * 546569Smckusic iget(dev, fs, ino) 554818Swnj dev_t dev; 566569Smckusic register struct fs *fs; 574818Swnj ino_t ino; 5824Sbill { 5924Sbill register struct inode *ip; 6024Sbill register struct mount *mp; 6124Sbill register struct buf *bp; 6224Sbill register struct dinode *dp; 6324Sbill register int slot; 6424Sbill 6524Sbill loop: 666569Smckusic if (getfs(dev) != fs) 676569Smckusic panic("iget: bad fs"); 6824Sbill slot = INOHASH(dev, ino); 6924Sbill ip = &inode[inohash[slot]]; 7024Sbill while (ip != &inode[-1]) { 714818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 724818Swnj if ((ip->i_flag&ILOCK) != 0) { 7324Sbill ip->i_flag |= IWANT; 7424Sbill sleep((caddr_t)ip, PINOD); 7524Sbill goto loop; 7624Sbill } 774818Swnj if ((ip->i_flag&IMOUNT) != 0) { 786569Smckusic for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 794818Swnj if (mp->m_inodp == ip) { 8024Sbill dev = mp->m_dev; 816569Smckusic fs = mp->m_bufp->b_un.b_fs; 8224Sbill ino = ROOTINO; 8324Sbill goto loop; 8424Sbill } 8524Sbill panic("no imt"); 8624Sbill } 8724Sbill ip->i_count++; 8824Sbill ip->i_flag |= ILOCK; 8924Sbill return(ip); 9024Sbill } 9124Sbill ip = &inode[ip->i_hlink]; 9224Sbill } 934818Swnj if (ifreel < 0) { 942933Swnj tablefull("inode"); 9524Sbill u.u_error = ENFILE; 9624Sbill return(NULL); 9724Sbill } 9824Sbill ip = &inode[ifreel]; 9924Sbill ifreel = ip->i_hlink; 10024Sbill ip->i_hlink = inohash[slot]; 10124Sbill inohash[slot] = ip - inode; 10224Sbill ip->i_dev = dev; 1036569Smckusic ip->i_fs = fs; 10424Sbill ip->i_number = ino; 10524Sbill ip->i_flag = ILOCK; 10624Sbill ip->i_count++; 1076569Smckusic ip->i_lastr = 0; 1086569Smckusic bp = bread(dev, fsbtodb(fs, itod(fs, ino)), fs->fs_bsize); 10924Sbill /* 11024Sbill * Check I/O errors 11124Sbill */ 1124818Swnj if ((bp->b_flags&B_ERROR) != 0) { 11324Sbill brelse(bp); 11424Sbill iput(ip); 11524Sbill return(NULL); 11624Sbill } 11724Sbill dp = bp->b_un.b_dino; 1186569Smckusic dp += itoo(fs, ino); 1196569Smckusic ip->i_ic = dp->di_ic; 12024Sbill brelse(bp); 1216569Smckusic return (ip); 12224Sbill } 12324Sbill 12424Sbill /* 12524Sbill * Decrement reference count of 12624Sbill * an inode structure. 12724Sbill * On the last reference, 12824Sbill * write the inode out and if necessary, 12924Sbill * truncate and deallocate the file. 13024Sbill */ 13124Sbill iput(ip) 1324818Swnj register struct inode *ip; 13324Sbill { 134*7118Smckusick 135*7118Smckusick if ((ip->i_flag & ILOCK) == 0) 136*7118Smckusick panic("iput"); 137*7118Smckusick iunlock(ip); 138*7118Smckusick irele(ip); 139*7118Smckusick } 140*7118Smckusick 141*7118Smckusick irele(ip) 142*7118Smckusick register struct inode *ip; 143*7118Smckusick { 14424Sbill register int i, x; 14524Sbill register struct inode *jp; 1466569Smckusic int mode; 14724Sbill 148*7118Smckusick if (ip->i_flag & ILOCK) 149*7118Smckusick panic("irele"); 1504818Swnj if (ip->i_count == 1) { 15124Sbill ip->i_flag |= ILOCK; 1524818Swnj if (ip->i_nlink <= 0) { 15324Sbill itrunc(ip); 1546569Smckusic mode = ip->i_mode; 15524Sbill ip->i_mode = 0; 15624Sbill ip->i_flag |= IUPD|ICHG; 1576569Smckusic ifree(ip, ip->i_number, mode); 15824Sbill } 1591203Sbill IUPDAT(ip, &time, &time, 0); 160*7118Smckusick iunlock(ip); 16124Sbill i = INOHASH(ip->i_dev, ip->i_number); 16224Sbill x = ip - inode; 16324Sbill if (inohash[i] == x) { 16424Sbill inohash[i] = ip->i_hlink; 16524Sbill } else { 16624Sbill for (jp = &inode[inohash[i]]; jp != &inode[-1]; 16724Sbill jp = &inode[jp->i_hlink]) 16824Sbill if (jp->i_hlink == x) { 16924Sbill jp->i_hlink = ip->i_hlink; 17024Sbill goto done; 17124Sbill } 17224Sbill panic("iput"); 17324Sbill } 17424Sbill done: 17524Sbill ip->i_hlink = ifreel; 17624Sbill ifreel = x; 17724Sbill ip->i_flag = 0; 17824Sbill ip->i_number = 0; 179*7118Smckusick } 18024Sbill ip->i_count--; 18124Sbill } 18224Sbill 18324Sbill /* 18424Sbill * Check accessed and update flags on 18524Sbill * an inode structure. 18624Sbill * If any is on, update the inode 18724Sbill * with the current time. 1881203Sbill * If waitfor is given, then must insure 1891203Sbill * i/o order so wait for write to complete. 19024Sbill */ 1911203Sbill iupdat(ip, ta, tm, waitfor) 1924818Swnj register struct inode *ip; 1934818Swnj time_t *ta, *tm; 1944818Swnj int waitfor; 19524Sbill { 19624Sbill register struct buf *bp; 19724Sbill struct dinode *dp; 1986569Smckusic register struct fs *fp; 19924Sbill 2006569Smckusic fp = ip->i_fs; 2016569Smckusic if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) { 2026569Smckusic if (fp->fs_ronly) 20324Sbill return; 2046569Smckusic bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 2056569Smckusic fp->fs_bsize); 20624Sbill if (bp->b_flags & B_ERROR) { 20724Sbill brelse(bp); 20824Sbill return; 20924Sbill } 2104818Swnj if (ip->i_flag&IACC) 2116569Smckusic ip->i_atime = *ta; 2124818Swnj if (ip->i_flag&IUPD) 2136569Smckusic ip->i_mtime = *tm; 2144818Swnj if (ip->i_flag&ICHG) 2156569Smckusic ip->i_ctime = time; 21624Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 2176569Smckusic dp = bp->b_un.b_dino + itoo(fp, ip->i_number); 2186569Smckusic dp->di_ic = ip->i_ic; 2191203Sbill if (waitfor) 2201203Sbill bwrite(bp); 2211203Sbill else 2221203Sbill bdwrite(bp); 22324Sbill } 22424Sbill } 22524Sbill 22624Sbill /* 22724Sbill * Free all the disk blocks associated 22824Sbill * with the specified inode structure. 22924Sbill * The blocks of the file are removed 23024Sbill * in reverse order. This FILO 23124Sbill * algorithm will tend to maintain 23224Sbill * a contiguous free list much longer 23324Sbill * than FIFO. 23424Sbill */ 23524Sbill itrunc(ip) 2364818Swnj register struct inode *ip; 23724Sbill { 23824Sbill register i; 23924Sbill dev_t dev; 24024Sbill daddr_t bn; 2411203Sbill struct inode itmp; 2426569Smckusic register struct fs *fs; 24324Sbill 24424Sbill i = ip->i_mode & IFMT; 2456569Smckusic if (i != IFREG && i != IFDIR && i != IFLNK) 24624Sbill return; 2471203Sbill /* 2481203Sbill * Clean inode on disk before freeing blocks 2491203Sbill * to insure no duplicates if system crashes. 2501203Sbill */ 2511203Sbill itmp = *ip; 2521203Sbill itmp.i_size = 0; 2536569Smckusic for (i = 0; i < NDADDR; i++) 2546569Smckusic itmp.i_db[i] = 0; 2556569Smckusic for (i = 0; i < NIADDR; i++) 2566569Smckusic itmp.i_ib[i] = 0; 2571203Sbill itmp.i_flag |= ICHG|IUPD; 2581203Sbill iupdat(&itmp, &time, &time, 1); 2591203Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 2601203Sbill 2611203Sbill /* 2621203Sbill * Now return blocks to free list... if machine 2631203Sbill * crashes, they will be harmless MISSING blocks. 2641203Sbill */ 26524Sbill dev = ip->i_dev; 2666569Smckusic fs = ip->i_fs; 2676569Smckusic /* 2686569Smckusic * release double indirect block first 2696569Smckusic */ 2706569Smckusic bn = ip->i_ib[NIADDR-1]; 2716569Smckusic if (bn != (daddr_t)0) { 2726569Smckusic ip->i_ib[NIADDR - 1] = (daddr_t)0; 2736569Smckusic tloop(ip, bn, 1); 2746569Smckusic } 2756569Smckusic /* 2766569Smckusic * release single indirect blocks second 2776569Smckusic */ 2786569Smckusic for (i = NIADDR - 2; i >= 0; i--) { 2796569Smckusic bn = ip->i_ib[i]; 2806569Smckusic if (bn != (daddr_t)0) { 2816569Smckusic ip->i_ib[i] = (daddr_t)0; 2826569Smckusic tloop(ip, bn, 0); 2836569Smckusic } 2846569Smckusic } 2856569Smckusic /* 2866569Smckusic * finally release direct blocks 2876569Smckusic */ 2886569Smckusic for (i = NDADDR - 1; i>=0; i--) { 2896569Smckusic bn = ip->i_db[i]; 2904818Swnj if (bn == (daddr_t)0) 29124Sbill continue; 2926569Smckusic ip->i_db[i] = (daddr_t)0; 2936569Smckusic fre(ip, bn, (off_t)blksize(fs, ip, i)); 29424Sbill } 29524Sbill ip->i_size = 0; 2961203Sbill /* 2971203Sbill * Inode was written and flags updated above. 2981203Sbill * No need to modify flags here. 2991203Sbill */ 30024Sbill } 30124Sbill 3026569Smckusic tloop(ip, bn, indflg) 3036569Smckusic register struct inode *ip; 3046569Smckusic daddr_t bn; 3056569Smckusic int indflg; 30624Sbill { 30724Sbill register i; 30824Sbill register struct buf *bp; 30924Sbill register daddr_t *bap; 3106569Smckusic register struct fs *fs; 31124Sbill daddr_t nb; 31224Sbill 31324Sbill bp = NULL; 3146569Smckusic fs = ip->i_fs; 3156569Smckusic for (i = NINDIR(fs) - 1; i >= 0; i--) { 3164818Swnj if (bp == NULL) { 3176569Smckusic bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize); 31824Sbill if (bp->b_flags & B_ERROR) { 31924Sbill brelse(bp); 32024Sbill return; 32124Sbill } 32224Sbill bap = bp->b_un.b_daddr; 32324Sbill } 32424Sbill nb = bap[i]; 3254818Swnj if (nb == (daddr_t)0) 32624Sbill continue; 3276569Smckusic if (indflg) 3286569Smckusic tloop(ip, nb, 0); 3296569Smckusic else 3306569Smckusic fre(ip, nb, fs->fs_bsize); 33124Sbill } 3324818Swnj if (bp != NULL) 33324Sbill brelse(bp); 3346569Smckusic fre(ip, bn, fs->fs_bsize); 33524Sbill } 33624Sbill 33724Sbill /* 33824Sbill * Make a new file. 33924Sbill */ 34024Sbill struct inode * 34124Sbill maknode(mode) 3426569Smckusic int mode; 34324Sbill { 34424Sbill register struct inode *ip; 3456569Smckusic ino_t ipref; 34624Sbill 3476569Smckusic if ((mode & IFMT) == IFDIR) 3486569Smckusic ipref = dirpref(u.u_pdir->i_fs); 3496569Smckusic else 3506569Smckusic ipref = u.u_pdir->i_number; 3516569Smckusic ip = ialloc(u.u_pdir, ipref, mode); 3524818Swnj if (ip == NULL) { 35324Sbill iput(u.u_pdir); 35424Sbill return(NULL); 35524Sbill } 35624Sbill ip->i_flag |= IACC|IUPD|ICHG; 3576569Smckusic if ((mode & IFMT) == 0) 35824Sbill mode |= IFREG; 35924Sbill ip->i_mode = mode & ~u.u_cmask; 36024Sbill ip->i_nlink = 1; 36124Sbill ip->i_uid = u.u_uid; 3625855Swnj ip->i_gid = u.u_pdir->i_gid; 3631203Sbill 3641203Sbill /* 3651203Sbill * Make sure inode goes to disk before directory entry. 3661203Sbill */ 3671203Sbill iupdat(ip, &time, &time, 1); 36824Sbill wdir(ip); 3696569Smckusic if (u.u_error) { 3706569Smckusic /* 3716569Smckusic * write error occurred trying to update directory 3726569Smckusic * so must deallocate the inode 3736569Smckusic */ 3746569Smckusic ip->i_nlink = 0; 3756569Smckusic ip->i_flag |= ICHG; 3766569Smckusic iput(ip); 3776569Smckusic return(NULL); 3786569Smckusic } 37924Sbill return(ip); 38024Sbill } 38124Sbill 38224Sbill /* 38324Sbill * Write a directory entry with 38424Sbill * parameters left as side effects 38524Sbill * to a call to namei. 38624Sbill */ 38724Sbill wdir(ip) 3884818Swnj struct inode *ip; 38924Sbill { 3906569Smckusic register struct direct *dp, *ndp; 3916569Smckusic struct fs *fs; 3926569Smckusic struct buf *bp; 3936569Smckusic int lbn, bn, base; 3946569Smckusic int loc, dsize, spccnt, newsize; 3956569Smckusic char *dirbuf; 39624Sbill 39724Sbill u.u_dent.d_ino = ip->i_number; 39824Sbill u.u_segflg = 1; 3996569Smckusic newsize = DIRSIZ(&u.u_dent); 4006569Smckusic /* 4016569Smckusic * if u.u_count == 0, a new directory block must be allocated. 4026569Smckusic */ 4036569Smckusic if (u.u_count == 0) { 4046569Smckusic u.u_dent.d_reclen = DIRBLKSIZ; 4056569Smckusic u.u_count = newsize; 4066569Smckusic u.u_base = (caddr_t)&u.u_dent; 4076569Smckusic writei(u.u_pdir); 4086569Smckusic iput(u.u_pdir); 4096569Smckusic return; 4106569Smckusic } 4116569Smckusic /* 4126569Smckusic * must read in an existing directory block 4136569Smckusic * to prepare to place the new entry into it. 4146569Smckusic */ 4156569Smckusic fs = u.u_pdir->i_fs; 4166569Smckusic lbn = lblkno(fs, u.u_offset); 4176569Smckusic base = blkoff(fs, u.u_offset); 4186569Smckusic bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count)); 4196569Smckusic if (u.u_offset + u.u_count > u.u_pdir->i_size) 4206569Smckusic u.u_pdir->i_size = u.u_offset + u.u_count; 4216569Smckusic bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn)); 4226569Smckusic if (bp->b_flags & B_ERROR) { 4236569Smckusic brelse(bp); 4246569Smckusic return; 4256569Smckusic } 4266569Smckusic dirbuf = bp->b_un.b_addr + base; 4276569Smckusic dp = (struct direct *)dirbuf; 4286569Smckusic dsize = DIRSIZ(dp); 4296569Smckusic spccnt = dp->d_reclen - dsize; 4306569Smckusic /* 4316569Smckusic * if there is insufficient room to make an entry at this point 4326569Smckusic * namei insures that compacting from u.u_offset for u.u_count 4336569Smckusic * bytes will provide the necessary space. 4346569Smckusic */ 4356569Smckusic for (loc = dp->d_reclen; loc < u.u_count; ) { 4366569Smckusic ndp = (struct direct *)(dirbuf + loc); 4376569Smckusic if (dp->d_ino == 0) { 4386569Smckusic spccnt += dsize; 4396569Smckusic } else { 4406569Smckusic dp->d_reclen = dsize; 4416569Smckusic dp = (struct direct *)((char *)dp + dsize); 4426569Smckusic } 4436569Smckusic dsize = DIRSIZ(ndp); 4446569Smckusic spccnt += ndp->d_reclen - dsize; 4456569Smckusic loc += ndp->d_reclen; 4466569Smckusic bcopy(ndp, dp, dsize); 4476569Smckusic } 4486569Smckusic /* 4496569Smckusic * Update the pointer fields in the previous entry (if any), 4506569Smckusic * copy in the new entry, and write out the block. 4516569Smckusic */ 4526569Smckusic if (dp->d_ino == 0) { 4536569Smckusic if (spccnt + dsize < newsize) 4546569Smckusic panic("wdir: compact failed"); 4556569Smckusic u.u_dent.d_reclen = spccnt + dsize; 4566569Smckusic } else { 4576569Smckusic if (spccnt < newsize) 4586569Smckusic panic("wdir: compact failed"); 4596569Smckusic u.u_dent.d_reclen = spccnt; 4606569Smckusic dp->d_reclen = dsize; 4616569Smckusic dp = (struct direct *)((char *)dp + dsize); 4626569Smckusic } 4636569Smckusic bcopy(&u.u_dent, dp, newsize); 4646569Smckusic bwrite(bp); 4656569Smckusic u.u_pdir->i_flag |= IUPD|ICHG; 46624Sbill iput(u.u_pdir); 46724Sbill } 4683617Sroot 4694818Swnj #ifdef ilock 4704818Swnj #undef ilock 4713617Sroot #endif 472*7118Smckusick #ifdef iunlock 473*7118Smckusick #undef iunlock 4743617Sroot #endif 4753617Sroot /* 4764818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 4773617Sroot */ 4784818Swnj ilock(ip) 4794818Swnj register struct inode *ip; 4803617Sroot { 4813617Sroot 4824818Swnj while (ip->i_flag&ILOCK) { 4833617Sroot ip->i_flag |= IWANT; 4843617Sroot sleep((caddr_t)ip, PINOD); 4853617Sroot } 4863617Sroot ip->i_flag |= ILOCK; 4873617Sroot } 4883617Sroot 4893617Sroot /* 4904818Swnj * Unlock an inode. If WANT bit is on, wakeup. 4913617Sroot */ 492*7118Smckusick iunlock(ip) 4934818Swnj register struct inode *ip; 4943617Sroot { 4953617Sroot 4963617Sroot ip->i_flag &= ~ILOCK; 4974818Swnj if (ip->i_flag&IWANT) { 4983617Sroot ip->i_flag &= ~IWANT; 4993617Sroot wakeup((caddr_t)ip); 5003617Sroot } 5013617Sroot } 502