1*6569Smckusic /* lfs_inode.c 4.10 82/04/19 */ 224Sbill 3*6569Smckusic /* merged into kernel: @(#)iget.c 2.2 4/8/82 */ 4*6569Smckusic 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" 11*6569Smckusic #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 * 54*6569Smckusic iget(dev, fs, ino) 554818Swnj dev_t dev; 56*6569Smckusic 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: 66*6569Smckusic if (getfs(dev) != fs) 67*6569Smckusic 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) { 78*6569Smckusic for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 794818Swnj if (mp->m_inodp == ip) { 8024Sbill dev = mp->m_dev; 81*6569Smckusic 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; 103*6569Smckusic ip->i_fs = fs; 10424Sbill ip->i_number = ino; 10524Sbill ip->i_flag = ILOCK; 10624Sbill ip->i_count++; 107*6569Smckusic ip->i_lastr = 0; 108*6569Smckusic 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; 118*6569Smckusic dp += itoo(fs, ino); 119*6569Smckusic ip->i_ic = dp->di_ic; 12024Sbill brelse(bp); 121*6569Smckusic 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 { 13424Sbill register int i, x; 13524Sbill register struct inode *jp; 136*6569Smckusic int mode; 13724Sbill 1384818Swnj if (ip->i_count == 1) { 13924Sbill ip->i_flag |= ILOCK; 1404818Swnj if (ip->i_nlink <= 0) { 14124Sbill itrunc(ip); 142*6569Smckusic mode = ip->i_mode; 14324Sbill ip->i_mode = 0; 14424Sbill ip->i_flag |= IUPD|ICHG; 145*6569Smckusic ifree(ip, ip->i_number, mode); 14624Sbill } 1471203Sbill IUPDAT(ip, &time, &time, 0); 1484818Swnj irele(ip); 14924Sbill i = INOHASH(ip->i_dev, ip->i_number); 15024Sbill x = ip - inode; 15124Sbill if (inohash[i] == x) { 15224Sbill inohash[i] = ip->i_hlink; 15324Sbill } else { 15424Sbill for (jp = &inode[inohash[i]]; jp != &inode[-1]; 15524Sbill jp = &inode[jp->i_hlink]) 15624Sbill if (jp->i_hlink == x) { 15724Sbill jp->i_hlink = ip->i_hlink; 15824Sbill goto done; 15924Sbill } 16024Sbill panic("iput"); 16124Sbill } 16224Sbill done: 16324Sbill ip->i_hlink = ifreel; 16424Sbill ifreel = x; 16524Sbill ip->i_flag = 0; 16624Sbill ip->i_number = 0; 16724Sbill } else 1684818Swnj irele(ip); 16924Sbill ip->i_count--; 17024Sbill } 17124Sbill 17224Sbill /* 17324Sbill * Check accessed and update flags on 17424Sbill * an inode structure. 17524Sbill * If any is on, update the inode 17624Sbill * with the current time. 1771203Sbill * If waitfor is given, then must insure 1781203Sbill * i/o order so wait for write to complete. 17924Sbill */ 1801203Sbill iupdat(ip, ta, tm, waitfor) 1814818Swnj register struct inode *ip; 1824818Swnj time_t *ta, *tm; 1834818Swnj int waitfor; 18424Sbill { 18524Sbill register struct buf *bp; 18624Sbill struct dinode *dp; 187*6569Smckusic register struct fs *fp; 18824Sbill 189*6569Smckusic fp = ip->i_fs; 190*6569Smckusic if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) { 191*6569Smckusic if (fp->fs_ronly) 19224Sbill return; 193*6569Smckusic bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 194*6569Smckusic fp->fs_bsize); 19524Sbill if (bp->b_flags & B_ERROR) { 19624Sbill brelse(bp); 19724Sbill return; 19824Sbill } 1994818Swnj if (ip->i_flag&IACC) 200*6569Smckusic ip->i_atime = *ta; 2014818Swnj if (ip->i_flag&IUPD) 202*6569Smckusic ip->i_mtime = *tm; 2034818Swnj if (ip->i_flag&ICHG) 204*6569Smckusic ip->i_ctime = time; 20524Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 206*6569Smckusic dp = bp->b_un.b_dino + itoo(fp, ip->i_number); 207*6569Smckusic dp->di_ic = ip->i_ic; 2081203Sbill if (waitfor) 2091203Sbill bwrite(bp); 2101203Sbill else 2111203Sbill bdwrite(bp); 21224Sbill } 21324Sbill } 21424Sbill 21524Sbill /* 21624Sbill * Free all the disk blocks associated 21724Sbill * with the specified inode structure. 21824Sbill * The blocks of the file are removed 21924Sbill * in reverse order. This FILO 22024Sbill * algorithm will tend to maintain 22124Sbill * a contiguous free list much longer 22224Sbill * than FIFO. 22324Sbill */ 22424Sbill itrunc(ip) 2254818Swnj register struct inode *ip; 22624Sbill { 22724Sbill register i; 22824Sbill dev_t dev; 22924Sbill daddr_t bn; 2301203Sbill struct inode itmp; 231*6569Smckusic register struct fs *fs; 23224Sbill 23324Sbill i = ip->i_mode & IFMT; 234*6569Smckusic if (i != IFREG && i != IFDIR && i != IFLNK) 23524Sbill return; 2361203Sbill /* 2371203Sbill * Clean inode on disk before freeing blocks 2381203Sbill * to insure no duplicates if system crashes. 2391203Sbill */ 2401203Sbill itmp = *ip; 2411203Sbill itmp.i_size = 0; 242*6569Smckusic for (i = 0; i < NDADDR; i++) 243*6569Smckusic itmp.i_db[i] = 0; 244*6569Smckusic for (i = 0; i < NIADDR; i++) 245*6569Smckusic itmp.i_ib[i] = 0; 2461203Sbill itmp.i_flag |= ICHG|IUPD; 2471203Sbill iupdat(&itmp, &time, &time, 1); 2481203Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 2491203Sbill 2501203Sbill /* 2511203Sbill * Now return blocks to free list... if machine 2521203Sbill * crashes, they will be harmless MISSING blocks. 2531203Sbill */ 25424Sbill dev = ip->i_dev; 255*6569Smckusic fs = ip->i_fs; 256*6569Smckusic /* 257*6569Smckusic * release double indirect block first 258*6569Smckusic */ 259*6569Smckusic bn = ip->i_ib[NIADDR-1]; 260*6569Smckusic if (bn != (daddr_t)0) { 261*6569Smckusic ip->i_ib[NIADDR - 1] = (daddr_t)0; 262*6569Smckusic tloop(ip, bn, 1); 263*6569Smckusic } 264*6569Smckusic /* 265*6569Smckusic * release single indirect blocks second 266*6569Smckusic */ 267*6569Smckusic for (i = NIADDR - 2; i >= 0; i--) { 268*6569Smckusic bn = ip->i_ib[i]; 269*6569Smckusic if (bn != (daddr_t)0) { 270*6569Smckusic ip->i_ib[i] = (daddr_t)0; 271*6569Smckusic tloop(ip, bn, 0); 272*6569Smckusic } 273*6569Smckusic } 274*6569Smckusic /* 275*6569Smckusic * finally release direct blocks 276*6569Smckusic */ 277*6569Smckusic for (i = NDADDR - 1; i>=0; i--) { 278*6569Smckusic bn = ip->i_db[i]; 2794818Swnj if (bn == (daddr_t)0) 28024Sbill continue; 281*6569Smckusic ip->i_db[i] = (daddr_t)0; 282*6569Smckusic fre(ip, bn, (off_t)blksize(fs, ip, i)); 28324Sbill } 28424Sbill ip->i_size = 0; 2851203Sbill /* 2861203Sbill * Inode was written and flags updated above. 2871203Sbill * No need to modify flags here. 2881203Sbill */ 28924Sbill } 29024Sbill 291*6569Smckusic tloop(ip, bn, indflg) 292*6569Smckusic register struct inode *ip; 293*6569Smckusic daddr_t bn; 294*6569Smckusic int indflg; 29524Sbill { 29624Sbill register i; 29724Sbill register struct buf *bp; 29824Sbill register daddr_t *bap; 299*6569Smckusic register struct fs *fs; 30024Sbill daddr_t nb; 30124Sbill 30224Sbill bp = NULL; 303*6569Smckusic fs = ip->i_fs; 304*6569Smckusic for (i = NINDIR(fs) - 1; i >= 0; i--) { 3054818Swnj if (bp == NULL) { 306*6569Smckusic bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize); 30724Sbill if (bp->b_flags & B_ERROR) { 30824Sbill brelse(bp); 30924Sbill return; 31024Sbill } 31124Sbill bap = bp->b_un.b_daddr; 31224Sbill } 31324Sbill nb = bap[i]; 3144818Swnj if (nb == (daddr_t)0) 31524Sbill continue; 316*6569Smckusic if (indflg) 317*6569Smckusic tloop(ip, nb, 0); 318*6569Smckusic else 319*6569Smckusic fre(ip, nb, fs->fs_bsize); 32024Sbill } 3214818Swnj if (bp != NULL) 32224Sbill brelse(bp); 323*6569Smckusic fre(ip, bn, fs->fs_bsize); 32424Sbill } 32524Sbill 32624Sbill /* 32724Sbill * Make a new file. 32824Sbill */ 32924Sbill struct inode * 33024Sbill maknode(mode) 331*6569Smckusic int mode; 33224Sbill { 33324Sbill register struct inode *ip; 334*6569Smckusic ino_t ipref; 33524Sbill 336*6569Smckusic if ((mode & IFMT) == IFDIR) 337*6569Smckusic ipref = dirpref(u.u_pdir->i_fs); 338*6569Smckusic else 339*6569Smckusic ipref = u.u_pdir->i_number; 340*6569Smckusic ip = ialloc(u.u_pdir, ipref, mode); 3414818Swnj if (ip == NULL) { 34224Sbill iput(u.u_pdir); 34324Sbill return(NULL); 34424Sbill } 34524Sbill ip->i_flag |= IACC|IUPD|ICHG; 346*6569Smckusic if ((mode & IFMT) == 0) 34724Sbill mode |= IFREG; 34824Sbill ip->i_mode = mode & ~u.u_cmask; 34924Sbill ip->i_nlink = 1; 35024Sbill ip->i_uid = u.u_uid; 3515855Swnj ip->i_gid = u.u_pdir->i_gid; 3521203Sbill 3531203Sbill /* 3541203Sbill * Make sure inode goes to disk before directory entry. 3551203Sbill */ 3561203Sbill iupdat(ip, &time, &time, 1); 35724Sbill wdir(ip); 358*6569Smckusic if (u.u_error) { 359*6569Smckusic /* 360*6569Smckusic * write error occurred trying to update directory 361*6569Smckusic * so must deallocate the inode 362*6569Smckusic */ 363*6569Smckusic ip->i_nlink = 0; 364*6569Smckusic ip->i_flag |= ICHG; 365*6569Smckusic iput(ip); 366*6569Smckusic return(NULL); 367*6569Smckusic } 36824Sbill return(ip); 36924Sbill } 37024Sbill 37124Sbill /* 37224Sbill * Write a directory entry with 37324Sbill * parameters left as side effects 37424Sbill * to a call to namei. 37524Sbill */ 37624Sbill wdir(ip) 3774818Swnj struct inode *ip; 37824Sbill { 379*6569Smckusic register struct direct *dp, *ndp; 380*6569Smckusic struct fs *fs; 381*6569Smckusic struct buf *bp; 382*6569Smckusic int lbn, bn, base; 383*6569Smckusic int loc, dsize, spccnt, newsize; 384*6569Smckusic char *dirbuf; 38524Sbill 38624Sbill u.u_dent.d_ino = ip->i_number; 38724Sbill u.u_segflg = 1; 388*6569Smckusic newsize = DIRSIZ(&u.u_dent); 389*6569Smckusic /* 390*6569Smckusic * if u.u_count == 0, a new directory block must be allocated. 391*6569Smckusic */ 392*6569Smckusic if (u.u_count == 0) { 393*6569Smckusic u.u_dent.d_reclen = DIRBLKSIZ; 394*6569Smckusic u.u_count = newsize; 395*6569Smckusic u.u_base = (caddr_t)&u.u_dent; 396*6569Smckusic writei(u.u_pdir); 397*6569Smckusic iput(u.u_pdir); 398*6569Smckusic return; 399*6569Smckusic } 400*6569Smckusic /* 401*6569Smckusic * must read in an existing directory block 402*6569Smckusic * to prepare to place the new entry into it. 403*6569Smckusic */ 404*6569Smckusic fs = u.u_pdir->i_fs; 405*6569Smckusic lbn = lblkno(fs, u.u_offset); 406*6569Smckusic base = blkoff(fs, u.u_offset); 407*6569Smckusic bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count)); 408*6569Smckusic if (u.u_offset + u.u_count > u.u_pdir->i_size) 409*6569Smckusic u.u_pdir->i_size = u.u_offset + u.u_count; 410*6569Smckusic bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn)); 411*6569Smckusic if (bp->b_flags & B_ERROR) { 412*6569Smckusic brelse(bp); 413*6569Smckusic return; 414*6569Smckusic } 415*6569Smckusic dirbuf = bp->b_un.b_addr + base; 416*6569Smckusic dp = (struct direct *)dirbuf; 417*6569Smckusic dsize = DIRSIZ(dp); 418*6569Smckusic spccnt = dp->d_reclen - dsize; 419*6569Smckusic /* 420*6569Smckusic * if there is insufficient room to make an entry at this point 421*6569Smckusic * namei insures that compacting from u.u_offset for u.u_count 422*6569Smckusic * bytes will provide the necessary space. 423*6569Smckusic */ 424*6569Smckusic for (loc = dp->d_reclen; loc < u.u_count; ) { 425*6569Smckusic ndp = (struct direct *)(dirbuf + loc); 426*6569Smckusic if (dp->d_ino == 0) { 427*6569Smckusic spccnt += dsize; 428*6569Smckusic } else { 429*6569Smckusic dp->d_reclen = dsize; 430*6569Smckusic dp = (struct direct *)((char *)dp + dsize); 431*6569Smckusic } 432*6569Smckusic dsize = DIRSIZ(ndp); 433*6569Smckusic spccnt += ndp->d_reclen - dsize; 434*6569Smckusic loc += ndp->d_reclen; 435*6569Smckusic bcopy(ndp, dp, dsize); 436*6569Smckusic } 437*6569Smckusic /* 438*6569Smckusic * Update the pointer fields in the previous entry (if any), 439*6569Smckusic * copy in the new entry, and write out the block. 440*6569Smckusic */ 441*6569Smckusic if (dp->d_ino == 0) { 442*6569Smckusic if (spccnt + dsize < newsize) 443*6569Smckusic panic("wdir: compact failed"); 444*6569Smckusic u.u_dent.d_reclen = spccnt + dsize; 445*6569Smckusic } else { 446*6569Smckusic if (spccnt < newsize) 447*6569Smckusic panic("wdir: compact failed"); 448*6569Smckusic u.u_dent.d_reclen = spccnt; 449*6569Smckusic dp->d_reclen = dsize; 450*6569Smckusic dp = (struct direct *)((char *)dp + dsize); 451*6569Smckusic } 452*6569Smckusic bcopy(&u.u_dent, dp, newsize); 453*6569Smckusic bwrite(bp); 454*6569Smckusic u.u_pdir->i_flag |= IUPD|ICHG; 45524Sbill iput(u.u_pdir); 45624Sbill } 4573617Sroot 4584818Swnj #ifdef ilock 4594818Swnj #undef ilock 4603617Sroot #endif 4614818Swnj #ifdef irele 4624818Swnj #undef irele 4633617Sroot #endif 4643617Sroot /* 4654818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 4663617Sroot */ 4674818Swnj ilock(ip) 4684818Swnj register struct inode *ip; 4693617Sroot { 4703617Sroot 4714818Swnj while (ip->i_flag&ILOCK) { 4723617Sroot ip->i_flag |= IWANT; 4733617Sroot sleep((caddr_t)ip, PINOD); 4743617Sroot } 4753617Sroot ip->i_flag |= ILOCK; 4763617Sroot } 4773617Sroot 4783617Sroot /* 4794818Swnj * Unlock an inode. If WANT bit is on, wakeup. 4803617Sroot */ 4814818Swnj irele(ip) 4824818Swnj register struct inode *ip; 4833617Sroot { 4843617Sroot 4853617Sroot ip->i_flag &= ~ILOCK; 4864818Swnj if (ip->i_flag&IWANT) { 4873617Sroot ip->i_flag &= ~IWANT; 4883617Sroot wakeup((caddr_t)ip); 4893617Sroot } 4903617Sroot } 491