1*2737Swnj /* lfs_inode.c 4.2 02/26/81 */ 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; 27*2737Swnj register struct inode *ip = inode; 2824Sbill 2924Sbill ifreel = 0; 30*2737Swnj for (i = 0; i < ninode-1; i++, ip++) 31*2737Swnj ip->i_hlink = i+1; 32*2737Swnj 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) 4424Sbill dev_t dev; 4524Sbill 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 * printf warning: no inodes -- if the inode 6824Sbill * structure is full 6924Sbill * panic: no imt -- if the mounted file 7024Sbill * system is not in the mount table. 7124Sbill * "cannot happen" 7224Sbill */ 7324Sbill struct inode * 7424Sbill iget(dev, ino) 7524Sbill dev_t dev; 7624Sbill ino_t ino; 7724Sbill { 7824Sbill register struct inode *ip; 7924Sbill register struct mount *mp; 8024Sbill register struct buf *bp; 8124Sbill register struct dinode *dp; 8224Sbill register int slot; 8324Sbill 8424Sbill loop: 8524Sbill slot = INOHASH(dev, ino); 8624Sbill ip = &inode[inohash[slot]]; 8724Sbill while (ip != &inode[-1]) { 8824Sbill if(ino == ip->i_number && dev == ip->i_dev) { 8924Sbill if((ip->i_flag&ILOCK) != 0) { 9024Sbill ip->i_flag |= IWANT; 9124Sbill sleep((caddr_t)ip, PINOD); 9224Sbill goto loop; 9324Sbill } 9424Sbill if((ip->i_flag&IMOUNT) != 0) { 9524Sbill for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 9624Sbill if(mp->m_inodp == ip) { 9724Sbill dev = mp->m_dev; 9824Sbill ino = ROOTINO; 9924Sbill goto loop; 10024Sbill } 10124Sbill panic("no imt"); 10224Sbill } 10324Sbill ip->i_count++; 10424Sbill ip->i_flag |= ILOCK; 10524Sbill return(ip); 10624Sbill } 10724Sbill ip = &inode[ip->i_hlink]; 10824Sbill } 10924Sbill if(ifreel < 0) { 11024Sbill printf("Inode table overflow\n"); 11124Sbill u.u_error = ENFILE; 11224Sbill return(NULL); 11324Sbill } 11424Sbill ip = &inode[ifreel]; 11524Sbill ifreel = ip->i_hlink; 11624Sbill ip->i_hlink = inohash[slot]; 11724Sbill inohash[slot] = ip - inode; 11824Sbill ip->i_dev = dev; 11924Sbill ip->i_number = ino; 12024Sbill ip->i_flag = ILOCK; 12124Sbill ip->i_count++; 12224Sbill ip->i_un.i_lastr = 0; 12324Sbill bp = bread(dev, itod(ino)); 12424Sbill /* 12524Sbill * Check I/O errors 12624Sbill */ 12724Sbill if((bp->b_flags&B_ERROR) != 0) { 12824Sbill brelse(bp); 12924Sbill iput(ip); 13024Sbill return(NULL); 13124Sbill } 13224Sbill dp = bp->b_un.b_dino; 13324Sbill dp += itoo(ino); 13424Sbill iexpand(ip, dp); 13524Sbill brelse(bp); 13624Sbill return(ip); 13724Sbill } 13824Sbill 13924Sbill iexpand(ip, dp) 14024Sbill register struct inode *ip; 14124Sbill register struct dinode *dp; 14224Sbill { 14324Sbill register char *p1, *p2; 14424Sbill register int i; 14524Sbill 14624Sbill ip->i_mode = dp->di_mode; 14724Sbill ip->i_nlink = dp->di_nlink; 14824Sbill ip->i_uid = dp->di_uid; 14924Sbill ip->i_gid = dp->di_gid; 15024Sbill ip->i_size = dp->di_size; 15124Sbill p1 = (char *)ip->i_un.i_addr; 15224Sbill p2 = (char *)dp->di_addr; 15324Sbill for(i=0; i<NADDR; i++) { 15424Sbill *p1++ = *p2++; 15524Sbill *p1++ = *p2++; 15624Sbill *p1++ = *p2++; 15724Sbill *p1++ = 0; 15824Sbill } 15924Sbill } 16024Sbill 16124Sbill /* 16224Sbill * Decrement reference count of 16324Sbill * an inode structure. 16424Sbill * On the last reference, 16524Sbill * write the inode out and if necessary, 16624Sbill * truncate and deallocate the file. 16724Sbill */ 16824Sbill iput(ip) 16924Sbill register struct inode *ip; 17024Sbill { 17124Sbill register int i, x; 17224Sbill register struct inode *jp; 17324Sbill 17424Sbill if(ip->i_count == 1) { 17524Sbill ip->i_flag |= ILOCK; 17624Sbill if(ip->i_nlink <= 0) { 17724Sbill itrunc(ip); 17824Sbill ip->i_mode = 0; 17924Sbill ip->i_flag |= IUPD|ICHG; 18024Sbill ifree(ip->i_dev, ip->i_number); 18124Sbill } 1821203Sbill IUPDAT(ip, &time, &time, 0); 18324Sbill prele(ip); 18424Sbill i = INOHASH(ip->i_dev, ip->i_number); 18524Sbill x = ip - inode; 18624Sbill if (inohash[i] == x) { 18724Sbill inohash[i] = ip->i_hlink; 18824Sbill } else { 18924Sbill for (jp = &inode[inohash[i]]; jp != &inode[-1]; 19024Sbill jp = &inode[jp->i_hlink]) 19124Sbill if (jp->i_hlink == x) { 19224Sbill jp->i_hlink = ip->i_hlink; 19324Sbill goto done; 19424Sbill } 19524Sbill panic("iput"); 19624Sbill } 19724Sbill done: 19824Sbill ip->i_hlink = ifreel; 19924Sbill ifreel = x; 20024Sbill ip->i_flag = 0; 20124Sbill ip->i_number = 0; 20224Sbill } else 20324Sbill prele(ip); 20424Sbill ip->i_count--; 20524Sbill } 20624Sbill 20724Sbill /* 20824Sbill * Check accessed and update flags on 20924Sbill * an inode structure. 21024Sbill * If any is on, update the inode 21124Sbill * with the current time. 2121203Sbill * If waitfor is given, then must insure 2131203Sbill * i/o order so wait for write to complete. 21424Sbill */ 2151203Sbill iupdat(ip, ta, tm, waitfor) 21624Sbill register struct inode *ip; 21724Sbill time_t *ta, *tm; 2181203Sbill int waitfor; 21924Sbill { 22024Sbill register struct buf *bp; 22124Sbill struct dinode *dp; 22224Sbill register char *p1, *p2; 22324Sbill register int i; 22424Sbill 22524Sbill if((ip->i_flag&(IUPD|IACC|ICHG)) != 0) { 22624Sbill if(getfs(ip->i_dev)->s_ronly) 22724Sbill return; 22824Sbill bp = bread(ip->i_dev, itod(ip->i_number)); 22924Sbill if (bp->b_flags & B_ERROR) { 23024Sbill brelse(bp); 23124Sbill return; 23224Sbill } 23324Sbill dp = bp->b_un.b_dino; 23424Sbill dp += itoo(ip->i_number); 23524Sbill dp->di_mode = ip->i_mode; 23624Sbill dp->di_nlink = ip->i_nlink; 23724Sbill dp->di_uid = ip->i_uid; 23824Sbill dp->di_gid = ip->i_gid; 23924Sbill dp->di_size = ip->i_size; 24024Sbill p1 = (char *)dp->di_addr; 24124Sbill p2 = (char *)ip->i_un.i_addr; 24224Sbill for(i=0; i<NADDR; i++) { 24324Sbill *p1++ = *p2++; 24424Sbill *p1++ = *p2++; 24524Sbill *p1++ = *p2++; 24624Sbill if(*p2++ != 0 && (ip->i_mode&IFMT)!=IFMPC 24724Sbill && (ip->i_mode&IFMT)!=IFMPB) 24824Sbill printf("iaddress > 2^24\n"); 24924Sbill } 25024Sbill if(ip->i_flag&IACC) 25124Sbill dp->di_atime = *ta; 25224Sbill if(ip->i_flag&IUPD) 25324Sbill dp->di_mtime = *tm; 25424Sbill if(ip->i_flag&ICHG) 25524Sbill dp->di_ctime = time; 25624Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 2571203Sbill if (waitfor) 2581203Sbill bwrite(bp); 2591203Sbill else 2601203Sbill bdwrite(bp); 26124Sbill } 26224Sbill } 26324Sbill 26424Sbill /* 26524Sbill * Free all the disk blocks associated 26624Sbill * with the specified inode structure. 26724Sbill * The blocks of the file are removed 26824Sbill * in reverse order. This FILO 26924Sbill * algorithm will tend to maintain 27024Sbill * a contiguous free list much longer 27124Sbill * than FIFO. 27224Sbill */ 27324Sbill itrunc(ip) 27424Sbill register struct inode *ip; 27524Sbill { 27624Sbill register i; 27724Sbill dev_t dev; 27824Sbill daddr_t bn; 2791203Sbill struct inode itmp; 28024Sbill 28124Sbill if (ip->i_vfdcnt) 28224Sbill panic("itrunc"); 28324Sbill i = ip->i_mode & IFMT; 28424Sbill if (i!=IFREG && i!=IFDIR) 28524Sbill return; 2861203Sbill 2871203Sbill /* 2881203Sbill * Clean inode on disk before freeing blocks 2891203Sbill * to insure no duplicates if system crashes. 2901203Sbill */ 2911203Sbill itmp = *ip; 2921203Sbill itmp.i_size = 0; 2931203Sbill for (i = 0; i < NADDR; i++) 2941203Sbill itmp.i_un.i_addr[i] = 0; 2951203Sbill itmp.i_flag |= ICHG|IUPD; 2961203Sbill iupdat(&itmp, &time, &time, 1); 2971203Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 2981203Sbill 2991203Sbill /* 3001203Sbill * Now return blocks to free list... if machine 3011203Sbill * crashes, they will be harmless MISSING blocks. 3021203Sbill */ 30324Sbill dev = ip->i_dev; 30424Sbill for(i=NADDR-1; i>=0; i--) { 30524Sbill bn = ip->i_un.i_addr[i]; 30624Sbill if(bn == (daddr_t)0) 30724Sbill continue; 30824Sbill ip->i_un.i_addr[i] = (daddr_t)0; 30924Sbill switch(i) { 31024Sbill 31124Sbill default: 31224Sbill free(dev, bn); 31324Sbill break; 31424Sbill 31524Sbill case NADDR-3: 31624Sbill tloop(dev, bn, 0, 0); 31724Sbill break; 31824Sbill 31924Sbill case NADDR-2: 32024Sbill tloop(dev, bn, 1, 0); 32124Sbill break; 32224Sbill 32324Sbill case NADDR-1: 32424Sbill tloop(dev, bn, 1, 1); 32524Sbill } 32624Sbill } 32724Sbill ip->i_size = 0; 3281203Sbill /* 3291203Sbill * Inode was written and flags updated above. 3301203Sbill * No need to modify flags here. 3311203Sbill */ 33224Sbill } 33324Sbill 33424Sbill tloop(dev, bn, f1, f2) 33524Sbill dev_t dev; 33624Sbill daddr_t bn; 33724Sbill { 33824Sbill register i; 33924Sbill register struct buf *bp; 34024Sbill register daddr_t *bap; 34124Sbill daddr_t nb; 34224Sbill 34324Sbill bp = NULL; 34424Sbill for(i=NINDIR-1; i>=0; i--) { 34524Sbill if(bp == NULL) { 34624Sbill bp = bread(dev, bn); 34724Sbill if (bp->b_flags & B_ERROR) { 34824Sbill brelse(bp); 34924Sbill return; 35024Sbill } 35124Sbill bap = bp->b_un.b_daddr; 35224Sbill } 35324Sbill nb = bap[i]; 35424Sbill if(nb == (daddr_t)0) 35524Sbill continue; 35624Sbill if(f1) { 35724Sbill brelse(bp); 35824Sbill bp = NULL; 35924Sbill tloop(dev, nb, f2, 0); 36024Sbill } else 36124Sbill free(dev, nb); 36224Sbill } 36324Sbill if(bp != NULL) 36424Sbill brelse(bp); 36524Sbill free(dev, bn); 36624Sbill } 36724Sbill 36824Sbill /* 36924Sbill * Make a new file. 37024Sbill */ 37124Sbill struct inode * 37224Sbill maknode(mode) 37324Sbill { 37424Sbill register struct inode *ip; 37524Sbill 37624Sbill ip = ialloc(u.u_pdir->i_dev); 37724Sbill if(ip == NULL) { 37824Sbill iput(u.u_pdir); 37924Sbill return(NULL); 38024Sbill } 38124Sbill ip->i_flag |= IACC|IUPD|ICHG; 38224Sbill if((mode&IFMT) == 0) 38324Sbill mode |= IFREG; 38424Sbill ip->i_mode = mode & ~u.u_cmask; 38524Sbill ip->i_nlink = 1; 38624Sbill ip->i_uid = u.u_uid; 38724Sbill ip->i_gid = u.u_gid; 3881203Sbill 3891203Sbill /* 3901203Sbill * Make sure inode goes to disk before directory entry. 3911203Sbill */ 3921203Sbill iupdat(ip, &time, &time, 1); 3931203Sbill 39424Sbill wdir(ip); 39524Sbill return(ip); 39624Sbill } 39724Sbill 39824Sbill /* 39924Sbill * Write a directory entry with 40024Sbill * parameters left as side effects 40124Sbill * to a call to namei. 40224Sbill */ 40324Sbill wdir(ip) 40424Sbill struct inode *ip; 40524Sbill { 40624Sbill 40724Sbill u.u_dent.d_ino = ip->i_number; 40824Sbill bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ); 40924Sbill u.u_count = sizeof(struct direct); 41024Sbill u.u_segflg = 1; 41124Sbill u.u_base = (caddr_t)&u.u_dent; 41224Sbill writei(u.u_pdir); 41324Sbill iput(u.u_pdir); 41424Sbill } 415