1*5855Swnj /* lfs_inode.c 4.8 82/02/15 */ 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" 924Sbill #include "../h/ino.h" 1024Sbill #include "../h/filsys.h" 1124Sbill #include "../h/conf.h" 1224Sbill #include "../h/buf.h" 1324Sbill #include "../h/inline.h" 1424Sbill 1524Sbill #define INOHSZ 63 1624Sbill #define INOHASH(dev,ino) (((dev)+(ino))%INOHSZ) 1724Sbill short inohash[INOHSZ]; 1824Sbill short ifreel; 1924Sbill 2024Sbill /* 2124Sbill * Initialize hash links for inodes 2224Sbill * and build inode free list. 2324Sbill */ 2424Sbill ihinit() 2524Sbill { 2624Sbill register int i; 272737Swnj register struct inode *ip = inode; 2824Sbill 2924Sbill ifreel = 0; 302737Swnj for (i = 0; i < ninode-1; i++, ip++) 312737Swnj ip->i_hlink = i+1; 322737Swnj ip->i_hlink = -1; 3324Sbill for (i = 0; i < INOHSZ; i++) 3424Sbill inohash[i] = -1; 3524Sbill } 3624Sbill 3724Sbill /* 3824Sbill * Find an inode if it is incore. 3924Sbill * This is the equivalent, for inodes, 4024Sbill * of ``incore'' in bio.c or ``pfind'' in subr.c. 4124Sbill */ 4224Sbill struct inode * 4324Sbill ifind(dev, ino) 444818Swnj dev_t dev; 454818Swnj ino_t ino; 4624Sbill { 4724Sbill register struct inode *ip; 4824Sbill 4924Sbill for (ip = &inode[inohash[INOHASH(dev,ino)]]; ip != &inode[-1]; 5024Sbill ip = &inode[ip->i_hlink]) 5124Sbill if (ino==ip->i_number && dev==ip->i_dev) 5224Sbill return (ip); 5324Sbill return ((struct inode *)0); 5424Sbill } 5524Sbill 5624Sbill /* 5724Sbill * Look up an inode by device,inumber. 5824Sbill * If it is in core (in the inode structure), 5924Sbill * honor the locking protocol. 6024Sbill * If it is not in core, read it in from the 6124Sbill * specified device. 6224Sbill * If the inode is mounted on, perform 6324Sbill * the indicated indirection. 6424Sbill * In all cases, a pointer to a locked 6524Sbill * inode structure is returned. 6624Sbill * 6724Sbill * panic: no imt -- if the mounted file 6824Sbill * system is not in the mount table. 6924Sbill * "cannot happen" 7024Sbill */ 7124Sbill struct inode * 7224Sbill iget(dev, ino) 734818Swnj dev_t dev; 744818Swnj ino_t ino; 7524Sbill { 7624Sbill register struct inode *ip; 7724Sbill register struct mount *mp; 7824Sbill register struct buf *bp; 7924Sbill register struct dinode *dp; 8024Sbill register int slot; 8124Sbill 8224Sbill loop: 8324Sbill slot = INOHASH(dev, ino); 8424Sbill ip = &inode[inohash[slot]]; 8524Sbill while (ip != &inode[-1]) { 864818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 874818Swnj if ((ip->i_flag&ILOCK) != 0) { 8824Sbill ip->i_flag |= IWANT; 8924Sbill sleep((caddr_t)ip, PINOD); 9024Sbill goto loop; 9124Sbill } 924818Swnj if ((ip->i_flag&IMOUNT) != 0) { 9324Sbill for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 944818Swnj if (mp->m_inodp == ip) { 9524Sbill dev = mp->m_dev; 9624Sbill ino = ROOTINO; 9724Sbill goto loop; 9824Sbill } 9924Sbill panic("no imt"); 10024Sbill } 10124Sbill ip->i_count++; 10224Sbill ip->i_flag |= ILOCK; 10324Sbill return(ip); 10424Sbill } 10524Sbill ip = &inode[ip->i_hlink]; 10624Sbill } 1074818Swnj if (ifreel < 0) { 1082933Swnj tablefull("inode"); 10924Sbill u.u_error = ENFILE; 11024Sbill return(NULL); 11124Sbill } 11224Sbill ip = &inode[ifreel]; 11324Sbill ifreel = ip->i_hlink; 11424Sbill ip->i_hlink = inohash[slot]; 11524Sbill inohash[slot] = ip - inode; 11624Sbill ip->i_dev = dev; 11724Sbill ip->i_number = ino; 11824Sbill ip->i_flag = ILOCK; 11924Sbill ip->i_count++; 12024Sbill ip->i_un.i_lastr = 0; 12124Sbill bp = bread(dev, itod(ino)); 12224Sbill /* 12324Sbill * Check I/O errors 12424Sbill */ 1254818Swnj if ((bp->b_flags&B_ERROR) != 0) { 12624Sbill brelse(bp); 12724Sbill iput(ip); 12824Sbill return(NULL); 12924Sbill } 13024Sbill dp = bp->b_un.b_dino; 13124Sbill dp += itoo(ino); 13224Sbill iexpand(ip, dp); 13324Sbill brelse(bp); 13424Sbill return(ip); 13524Sbill } 13624Sbill 13724Sbill iexpand(ip, dp) 1384818Swnj register struct inode *ip; 1394818Swnj register struct dinode *dp; 14024Sbill { 14124Sbill register char *p1, *p2; 14224Sbill register int i; 14324Sbill 14424Sbill ip->i_mode = dp->di_mode; 14524Sbill ip->i_nlink = dp->di_nlink; 14624Sbill ip->i_uid = dp->di_uid; 14724Sbill ip->i_gid = dp->di_gid; 14824Sbill ip->i_size = dp->di_size; 14924Sbill p1 = (char *)ip->i_un.i_addr; 15024Sbill p2 = (char *)dp->di_addr; 15124Sbill for(i=0; i<NADDR; i++) { 15224Sbill *p1++ = *p2++; 15324Sbill *p1++ = *p2++; 15424Sbill *p1++ = *p2++; 15524Sbill *p1++ = 0; 15624Sbill } 15724Sbill } 15824Sbill 15924Sbill /* 16024Sbill * Decrement reference count of 16124Sbill * an inode structure. 16224Sbill * On the last reference, 16324Sbill * write the inode out and if necessary, 16424Sbill * truncate and deallocate the file. 16524Sbill */ 16624Sbill iput(ip) 1674818Swnj register struct inode *ip; 16824Sbill { 16924Sbill register int i, x; 17024Sbill register struct inode *jp; 17124Sbill 1724818Swnj if (ip->i_count == 1) { 17324Sbill ip->i_flag |= ILOCK; 1744818Swnj if (ip->i_nlink <= 0) { 17524Sbill itrunc(ip); 17624Sbill ip->i_mode = 0; 17724Sbill ip->i_flag |= IUPD|ICHG; 17824Sbill ifree(ip->i_dev, ip->i_number); 17924Sbill } 1801203Sbill IUPDAT(ip, &time, &time, 0); 1814818Swnj irele(ip); 18224Sbill i = INOHASH(ip->i_dev, ip->i_number); 18324Sbill x = ip - inode; 18424Sbill if (inohash[i] == x) { 18524Sbill inohash[i] = ip->i_hlink; 18624Sbill } else { 18724Sbill for (jp = &inode[inohash[i]]; jp != &inode[-1]; 18824Sbill jp = &inode[jp->i_hlink]) 18924Sbill if (jp->i_hlink == x) { 19024Sbill jp->i_hlink = ip->i_hlink; 19124Sbill goto done; 19224Sbill } 19324Sbill panic("iput"); 19424Sbill } 19524Sbill done: 19624Sbill ip->i_hlink = ifreel; 19724Sbill ifreel = x; 19824Sbill ip->i_flag = 0; 19924Sbill ip->i_number = 0; 20024Sbill } else 2014818Swnj irele(ip); 20224Sbill ip->i_count--; 20324Sbill } 20424Sbill 20524Sbill /* 20624Sbill * Check accessed and update flags on 20724Sbill * an inode structure. 20824Sbill * If any is on, update the inode 20924Sbill * with the current time. 2101203Sbill * If waitfor is given, then must insure 2111203Sbill * i/o order so wait for write to complete. 21224Sbill */ 2131203Sbill iupdat(ip, ta, tm, waitfor) 2144818Swnj register struct inode *ip; 2154818Swnj time_t *ta, *tm; 2164818Swnj int waitfor; 21724Sbill { 21824Sbill register struct buf *bp; 21924Sbill struct dinode *dp; 22024Sbill register char *p1, *p2; 22124Sbill register int i; 22224Sbill 2234818Swnj if ((ip->i_flag&(IUPD|IACC|ICHG)) != 0) { 2244818Swnj if (getfs(ip->i_dev)->s_ronly) 22524Sbill return; 22624Sbill bp = bread(ip->i_dev, itod(ip->i_number)); 22724Sbill if (bp->b_flags & B_ERROR) { 22824Sbill brelse(bp); 22924Sbill return; 23024Sbill } 23124Sbill dp = bp->b_un.b_dino; 23224Sbill dp += itoo(ip->i_number); 23324Sbill dp->di_mode = ip->i_mode; 23424Sbill dp->di_nlink = ip->i_nlink; 23524Sbill dp->di_uid = ip->i_uid; 23624Sbill dp->di_gid = ip->i_gid; 23724Sbill dp->di_size = ip->i_size; 23824Sbill p1 = (char *)dp->di_addr; 23924Sbill p2 = (char *)ip->i_un.i_addr; 24024Sbill for(i=0; i<NADDR; i++) { 24124Sbill *p1++ = *p2++; 24224Sbill *p1++ = *p2++; 24324Sbill *p1++ = *p2++; 2444818Swnj if (*p2++ != 0) 24524Sbill printf("iaddress > 2^24\n"); 24624Sbill } 2474818Swnj if (ip->i_flag&IACC) 24824Sbill dp->di_atime = *ta; 2494818Swnj if (ip->i_flag&IUPD) 25024Sbill dp->di_mtime = *tm; 2514818Swnj if (ip->i_flag&ICHG) 25224Sbill dp->di_ctime = time; 25324Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 2541203Sbill if (waitfor) 2551203Sbill bwrite(bp); 2561203Sbill else 2571203Sbill bdwrite(bp); 25824Sbill } 25924Sbill } 26024Sbill 26124Sbill /* 26224Sbill * Free all the disk blocks associated 26324Sbill * with the specified inode structure. 26424Sbill * The blocks of the file are removed 26524Sbill * in reverse order. This FILO 26624Sbill * algorithm will tend to maintain 26724Sbill * a contiguous free list much longer 26824Sbill * than FIFO. 26924Sbill */ 27024Sbill itrunc(ip) 2714818Swnj register struct inode *ip; 27224Sbill { 27324Sbill register i; 27424Sbill dev_t dev; 27524Sbill daddr_t bn; 2761203Sbill struct inode itmp; 27724Sbill 27824Sbill i = ip->i_mode & IFMT; 27924Sbill if (i!=IFREG && i!=IFDIR) 28024Sbill return; 2811203Sbill 2821203Sbill /* 2831203Sbill * Clean inode on disk before freeing blocks 2841203Sbill * to insure no duplicates if system crashes. 2851203Sbill */ 2861203Sbill itmp = *ip; 2871203Sbill itmp.i_size = 0; 2881203Sbill for (i = 0; i < NADDR; i++) 2891203Sbill itmp.i_un.i_addr[i] = 0; 2901203Sbill itmp.i_flag |= ICHG|IUPD; 2911203Sbill iupdat(&itmp, &time, &time, 1); 2921203Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 2931203Sbill 2941203Sbill /* 2951203Sbill * Now return blocks to free list... if machine 2961203Sbill * crashes, they will be harmless MISSING blocks. 2971203Sbill */ 29824Sbill dev = ip->i_dev; 29924Sbill for(i=NADDR-1; i>=0; i--) { 30024Sbill bn = ip->i_un.i_addr[i]; 3014818Swnj if (bn == (daddr_t)0) 30224Sbill continue; 30324Sbill ip->i_un.i_addr[i] = (daddr_t)0; 30424Sbill switch(i) { 30524Sbill 30624Sbill default: 30724Sbill free(dev, bn); 30824Sbill break; 30924Sbill 31024Sbill case NADDR-3: 31124Sbill tloop(dev, bn, 0, 0); 31224Sbill break; 31324Sbill 31424Sbill case NADDR-2: 31524Sbill tloop(dev, bn, 1, 0); 31624Sbill break; 31724Sbill 31824Sbill case NADDR-1: 31924Sbill tloop(dev, bn, 1, 1); 32024Sbill } 32124Sbill } 32224Sbill ip->i_size = 0; 3231203Sbill /* 3241203Sbill * Inode was written and flags updated above. 3251203Sbill * No need to modify flags here. 3261203Sbill */ 32724Sbill } 32824Sbill 32924Sbill tloop(dev, bn, f1, f2) 33024Sbill dev_t dev; 33124Sbill daddr_t bn; 33224Sbill { 33324Sbill register i; 33424Sbill register struct buf *bp; 33524Sbill register daddr_t *bap; 33624Sbill daddr_t nb; 33724Sbill 33824Sbill bp = NULL; 33924Sbill for(i=NINDIR-1; i>=0; i--) { 3404818Swnj if (bp == NULL) { 34124Sbill bp = bread(dev, bn); 34224Sbill if (bp->b_flags & B_ERROR) { 34324Sbill brelse(bp); 34424Sbill return; 34524Sbill } 34624Sbill bap = bp->b_un.b_daddr; 34724Sbill } 34824Sbill nb = bap[i]; 3494818Swnj if (nb == (daddr_t)0) 35024Sbill continue; 3514818Swnj if (f1) { 35224Sbill brelse(bp); 35324Sbill bp = NULL; 35424Sbill tloop(dev, nb, f2, 0); 35524Sbill } else 35624Sbill free(dev, nb); 35724Sbill } 3584818Swnj if (bp != NULL) 35924Sbill brelse(bp); 36024Sbill free(dev, bn); 36124Sbill } 36224Sbill 36324Sbill /* 36424Sbill * Make a new file. 36524Sbill */ 36624Sbill struct inode * 36724Sbill maknode(mode) 36824Sbill { 36924Sbill register struct inode *ip; 37024Sbill 37124Sbill ip = ialloc(u.u_pdir->i_dev); 3724818Swnj if (ip == NULL) { 37324Sbill iput(u.u_pdir); 37424Sbill return(NULL); 37524Sbill } 37624Sbill ip->i_flag |= IACC|IUPD|ICHG; 3774818Swnj if ((mode&IFMT) == 0) 37824Sbill mode |= IFREG; 37924Sbill ip->i_mode = mode & ~u.u_cmask; 38024Sbill ip->i_nlink = 1; 38124Sbill ip->i_uid = u.u_uid; 382*5855Swnj ip->i_gid = u.u_pdir->i_gid; 3831203Sbill 3841203Sbill /* 3851203Sbill * Make sure inode goes to disk before directory entry. 3861203Sbill */ 3871203Sbill iupdat(ip, &time, &time, 1); 3881203Sbill 38924Sbill wdir(ip); 39024Sbill return(ip); 39124Sbill } 39224Sbill 39324Sbill /* 39424Sbill * Write a directory entry with 39524Sbill * parameters left as side effects 39624Sbill * to a call to namei. 39724Sbill */ 39824Sbill wdir(ip) 3994818Swnj struct inode *ip; 40024Sbill { 40124Sbill 40224Sbill u.u_dent.d_ino = ip->i_number; 40324Sbill bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ); 40424Sbill u.u_count = sizeof(struct direct); 40524Sbill u.u_segflg = 1; 40624Sbill u.u_base = (caddr_t)&u.u_dent; 40724Sbill writei(u.u_pdir); 40824Sbill iput(u.u_pdir); 40924Sbill } 4103617Sroot 4114818Swnj #ifdef ilock 4124818Swnj #undef ilock 4133617Sroot #endif 4144818Swnj #ifdef irele 4154818Swnj #undef irele 4163617Sroot #endif 4173617Sroot /* 4184818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 4193617Sroot */ 4204818Swnj ilock(ip) 4214818Swnj register struct inode *ip; 4223617Sroot { 4233617Sroot 4244818Swnj while (ip->i_flag&ILOCK) { 4253617Sroot ip->i_flag |= IWANT; 4263617Sroot sleep((caddr_t)ip, PINOD); 4273617Sroot } 4283617Sroot ip->i_flag |= ILOCK; 4293617Sroot } 4303617Sroot 4313617Sroot /* 4324818Swnj * Unlock an inode. If WANT bit is on, wakeup. 4333617Sroot */ 4344818Swnj irele(ip) 4354818Swnj register struct inode *ip; 4363617Sroot { 4373617Sroot 4383617Sroot ip->i_flag &= ~ILOCK; 4394818Swnj if (ip->i_flag&IWANT) { 4403617Sroot ip->i_flag &= ~IWANT; 4413617Sroot wakeup((caddr_t)ip); 4423617Sroot } 4433617Sroot } 444