#include "../h/local.h" #ifdef SCCS_ID static char SCCS_ID [] = "%Z%%M% %I% %Y% %U% - %E% "; #endif SCCS_ID #include "../h/param.h" #include "../h/systm.h" #include "../h/mount.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/inode.h" #include "../h/ino.h" #include "../h/filsys.h" #include "../h/conf.h" #include "../h/buf.h" #ifdef UCB_QUOTAS #include "../h/quota.h" #endif UCB_QUOTAS #ifdef UCB_IHASH #define INOHSZ 64 /* must be multiple of two */ #define INOHASH(dev,ino) (((dev) + (ino)) & (INOHSZ - 1)) struct inode *ihash[INOHSZ] = { 0 }; struct inode *ifreelist; /* * Initialize hash links for inodes * and build inode free list. */ ihinit() { register i; register struct inode *ip; ifreelist = &inode[0]; for(ip = inode; ip < &inodeNINODE[-1]; ip++) ip->i_link = ip + 1; ip->i_link = (struct inode *) NULL; for(i = 0; i < INOHSZ; i++) ihash[i] = (struct inode *) NULL; } /* * Find an inode if it is incore. * This is the equivalent, for inodes, * of ``incore'' in bio.c or ``pfind'' in subr.c. */ struct inode * ifind(dev, ino) dev_t dev; ino_t ino; { register struct inode *ip; for (ip = ihash[INOHASH(dev,ino)]; ip != NULL; ip = ip->i_link) #ifdef USTEST if (USTOI(ino)==USTOI(ip->i_number) && dev==ip->i_dev) #else USTEST if (ino==ip->i_number && dev==ip->i_dev) #endif USTEST return (ip); return ((struct inode *)0); } #endif UCB_IHASH /* * Look up an inode by device,inumber. * If it is in core (in the inode structure), * honor the locking protocol. * If it is not in core, read it in from the * specified device. * If the inode is mounted on, perform * the indicated indirection. * In all cases, a pointer to a locked * inode structure is returned. * * printf warning: no inodes -- if the inode * structure is full * panic: no imt -- if the mounted file * system is not in the mount table. * "cannot happen" */ struct inode * iget(dev, ino) dev_t dev; ino_t ino; { register struct inode *ip; register struct mount *mp; #ifdef UCB_IHASH register int slot; #else UCB_IHASH register struct inode *oip; #endif UCB_IHASH register struct buf *bp; register struct dinode *dp; trace(0x08, "iget", (dev<<16)|ino); loop: slot = INOHASH(dev, ino); ip = ihash[slot]; while (ip != NULL) { if (USTOI(ino)==USTOI(ip->i_number) && dev==ip->i_dev) { again: if((ip->i_flag&ILOCK) != 0) { ip->i_flag |= IWANT; sleep((caddr_t)ip, PINOD); if ( USTOI(ino) == USTOI(ip->i_number) && dev == ip->i_dev) goto again; goto loop; } if((ip->i_flag&IMOUNT) != 0) { for(mp = &mount[0]; mp < mountNMOUNT; mp++) if(mp->m_inodp == ip) { dev = mp->m_dev; ino = ROOTINO; goto loop; } panic("no imt"); } ip->i_count++; ip->i_flag |= ILOCK; trace(0x08, "ip=", ip); return(ip); } ip = ip->i_link; } if (ifreelist == NULL) { printf("Inode table overflow\n"); u.u_error = ENFILE; trace(0x08, "ip=", NULL); return(NULL); } ip = ifreelist; ifreelist = ip->i_link; ip->i_link = ihash[slot]; ihash[slot] = ip; ip->i_dev = dev; ip->i_number = ino; ip->i_flag = ILOCK; ip->i_count++; ip->i_un.i_lastr = 0; bp = bread(dev, itod(ino)); /* * Check I/O errors */ if((bp->b_flags&B_ERROR) != 0) { brelse(bp); iput(ip); trace(0x08, "ip=", NULL); return(NULL); } dp = bp->b_un.b_dino; dp += itoo(ino); iexpand(ip, dp); brelse(bp); trace(0x08, "ip=", ip); return(ip); } iexpand(ip, dp) register struct inode *ip; register struct dinode *dp; { register char *p1; char *p2; int i; #ifdef V6 if (dp->di_mode == 0) ip->i_mode = 0; else { ip->i_mode = dp->di_mode & ~(DIALLOC|DILARG); if ((dp->di_mode&DIFMT) == 0) ip->i_mode |= IFREG; if (dp->di_mode&DILARG) ip->i_mode |= ILARG; } #else ip->i_mode = dp->di_mode; #endif ip->i_nlink = dp->di_nlink; ip->i_uid = dp->di_uid; ip->i_gid = dp->di_gid; #ifdef V6 ip->i_size = dp->di_size1; { register int *q1, *q2; q1 = ip->i_un.i_addr; q2 = dp->di_addr; for (i=0; ii_size = dp->di_size; p1 = (char *)ip->i_un.i_addr; p2 = (char *)dp->di_addr; for(i=0; ii_count == 1) { ip->i_flag |= ILOCK; if(ip->i_nlink <= 0) { itrunc(ip); ip->i_mode = 0; ip->i_flag |= IUPD|ICHG; ifree(ip->i_dev, ip->i_number); } #ifdef UCB_QUOTAS /* * EECS, UCB * Berkeley's quota system */ qp = ip->i_quot; if (qp != NULL) { ip->i_quot = NULL; qprint(01)("IPUT: qp = %d, ip = %d, i_flag = 0%o\n", qp->i_number, ip->i_number, ip->i_flag); } #endif UCB_QUOTAS #ifdef UCB_NODUPS iupdat(ip, &time, &time, 0); #else UCB_NODUPS iupdat(ip, &time, &time); #endif UCB_NODUPS prele(ip); #ifdef UCB_IHASH i = INOHASH(ip->i_dev, ip->i_number); if (ihash[i] == ip) ihash[i] = ip->i_link; else { for (jp = ihash[i]; jp != NULL; jp = jp->i_link) if (jp->i_link == ip) { jp->i_link = ip->i_link; goto done; } panic("iput"); } done: ip->i_link = ifreelist; ifreelist = ip; #endif UCB_IHASH ip->i_flag = 0; ip->i_number = 0; } #ifdef UCB_IHASH else prele(ip); ip->i_count--; #else UCB_IHASH ip->i_count--; prele(ip); #endif UCB_IHASH #ifdef UCB_QUOTAS if (isquot(ip)) qprint(01)("IPUT: decremented count of quota %d\n", ip->i_number); } while ((ip = qp) != NULL); #endif UCB_QUOTAS } /* * Check accessed and update flags on * an inode structure. * If any are on, update the inode * with the current time. #ifdef UCB_NODUPS * If waitfor set, then must insure * i/o order by waiting for the write * to complete. #endif UCB_NODUPS */ #ifdef UCB_NODUPS iupdat(ip, ta, tm, waitfor) #else UCB_NODUPS iupdat(ip, ta, tm) #endif UCB_NODUPS register struct inode *ip; time_t *ta, *tm; #ifdef UCB_NODUPS int waitfor; #endif UCB_NODUPS { register struct buf *bp; struct dinode *dp; register char *p1; char *p2; int i; if((ip->i_flag&(IUPD|IACC|ICHG)) != 0) { if(getfs(ip->i_dev)->s_ronly) return; bp = bread(ip->i_dev, itod(ip->i_number)); if (bp->b_flags & B_ERROR) { brelse(bp); return; } dp = bp->b_un.b_dino; dp += itoo(ip->i_number); #ifdef V6 dp->di_mode = ip->i_mode & ~(ILARG|DIALLOC|DILARG); if (ip->i_mode != 0) dp->di_mode |= DIALLOC; if (ip->i_mode&ILARG) dp->di_mode |= DILARG; #else dp->di_mode = ip->i_mode; #endif dp->di_nlink = ip->i_nlink; dp->di_uid = ip->i_uid; dp->di_gid = ip->i_gid; #ifdef V6 dp->di_size1 = ip->i_size; { register int *q1, *q2; q1 = dp->di_addr; q2 = ip->i_un.i_addr; for (i=0; ii_flag&IACC) dp->di_atime = *ta; if(ip->i_flag&IUPD) dp->di_mtime = *tm; #else V6 dp->di_size = ip->i_size; p1 = (char *)dp->di_addr; p2 = (char *)ip->i_un.i_addr; for(i=0; ii_mode&IFMT)!=IFMPC && (ip->i_mode&IFMT)!=IFMPB) #ifdef UCB_DEVERR printf("iaddress[%d] > 2^24(%D), i_number = %d, i_dev = %d\n", i, ip->i_un.i_addr[i], ip->i_number, ip->i_dev); #else UCB_DEVERR printf("iaddress > 2^24\n"); #endif UCB_DEVERR #else DEC if(*p2++ != 0 && (ip->i_mode&IFMT)!=IFMPC && (ip->i_mode&IFMT)!=IFMPB) #ifdef UCB_DEVERR printf("iaddress[%d] > 2^24(%D), i_number = %d, i_dev = %d\n", i, ip->i_un.i_addr[i], ip->i_number, ip->i_dev); #else UCB_DEVERR printf("iaddress > 2^24\n"); #endif UCB_DEVERR *p1++ = *p2++; #endif DEC *p1++ = *p2++; *p1++ = *p2++; } if(ip->i_flag&IACC) dp->di_atime = *ta; if(ip->i_flag&IUPD) dp->di_mtime = *tm; if(ip->i_flag&ICHG) dp->di_ctime = time; #endif V6 ip->i_flag &= ~(IUPD|IACC|ICHG); #ifdef UCB_NODUPS if (waitfor) bwrite(bp); else bdwrite(bp); #else UCB_NODUPS bdwrite(bp); #endif UCB_NODUPS } } /* * Free all the disk blocks associated * with the specified inode structure. * The blocks of the file are removed * in reverse order. This FILO * algorithm will tend to maintain * a contiguous free list much longer * than FIFO. */ #ifdef V6 itrunc(rp) register struct inode *rp; { register *ip, *bp, *cp; register *dp, *ep; int i; i = rp->i_mode & IFMT; if (i!=IFREG && i!=IFDIR) return; for(ip = &rp->i_un.i_addr[7]; ip >= &rp->i_un.i_addr[0]; ip--) if(*ip) { if((rp->i_mode&ILARG) != 0) { bp = bread(rp->i_dev, *ip); for(cp = bp->b_un.b_addr+(BSIZE-NBPW); cp >= bp->b_un.b_addr; cp--) if(*cp) { if(ip == &rp->i_un.i_addr[7]) { dp = bread(rp->i_dev, *cp); for(ep = dp->b_un.b_addr+(BSIZE-NBPW); ep >= dp->b_un.b_addr; ep--) if(*ep) free(rp->i_dev, *ep); brelse(dp); } free(rp->i_dev, *cp); } brelse(bp); } free(rp->i_dev, *ip); *ip = 0; } rp->i_mode =& ~ILARG; rp->i_size = 0; rp->i_flag =| IUPD; } #else V6 itrunc(ip) register struct inode *ip; { register i; dev_t dev; daddr_t bn; #ifdef UCB_NODUPS struct inode itmp; #endif UCB_NODUPS i = ip->i_mode & IFMT; if (i!=IFREG && i!=IFDIR) return; #ifdef UCB_NODUPS /* * Clean inode on disk before freeing blocks * to insure no duplicates if system crashes. */ itmp = *ip; itmp.i_size = 0; for (i = 0; i < NADDR; i++) itmp.i_un.i_addr[i] = 0; itmp.i_flag |= ICHG|IUPD; iupdat(&itmp, &time, &time, 1); ip->i_flag &= ~(IUPD|IACC|ICHG); /* * Now return blocks to free list... if machine * crashes, they will be harmless MISSING blocks. */ #endif UCB_NODUPS dev = ip->i_dev; for(i=NADDR-1; i>=0; i--) { bn = ip->i_un.i_addr[i]; if(bn == (daddr_t)0) continue; ip->i_un.i_addr[i] = (daddr_t)0; switch(i) { default: #ifdef UCB_QUOTAS qfree(ip, bn); #else UCB_QUOTAS free(dev, bn); #endif UCB_QUOTAS break; case NADDR-3: #ifdef UCB_QUOTAS tloop(dev, bn, 0, 0, ip); #else UCB_QUOTAS tloop(dev, bn, 0, 0); #endif UCB_QUOTAS break; case NADDR-2: #ifdef UCB_QUOTAS tloop(dev, bn, 1, 0, ip); #else UCB_QUOTAS tloop(dev, bn, 1, 0); #endif UCB_QUOTAS break; case NADDR-1: #ifdef UCB_QUOTAS tloop(dev, bn, 1, 1, ip); #else UCB_QUOTAS tloop(dev, bn, 1, 1); #endif UCB_QUOTAS } } ip->i_size = 0; #ifndef UCB_NODUPS ip->i_flag |= ICHG|IUPD; #else UCB_NODUPS /* * Inode was written and flags updated above. * No need to modify flags here. */ #endif UCB_NODUPS } #ifdef UCB_QUOTAS tloop(dev, bn, f1, f2, ip) #else UCB_QUOTAS tloop(dev, bn, f1, f2) #endif UCB_QUOTAS dev_t dev; daddr_t bn; #ifdef UCB_QUOTAS struct inode *ip; #endif UCB_QUOTAS { register i; register struct buf *bp; register daddr_t *bap; daddr_t nb; bp = NULL; for(i=NINDIR-1; i>=0; i--) { if(bp == NULL) { bp = bread(dev, bn); if (bp->b_flags & B_ERROR) { brelse(bp); return; } bap = bp->b_un.b_daddr; } nb = bap[i]; if(nb == (daddr_t)0) continue; if(f1) { brelse(bp); bp = NULL; #ifdef UCB_QUOTAS tloop(dev, nb, f2, 0, ip); #else UCB_QUOTAS tloop(dev, nb, f2, 0); #endif UCB_QUOTAS } else #ifdef UCB_QUOTAS qfree(ip, nb); #else UCB_QUOTAS free(dev, nb); #endif UCB_QUOTAS } if(bp != NULL) brelse(bp); #ifdef UCB_QUOTAS qfree(ip, bn); #else UCB_QUOTAS free(dev, bn); #endif UCB_QUOTAS } #endif V6 /* * Make a new file. */ struct inode * maknode(mode) { register struct inode *ip; ip = ialloc(u.u_pdir->i_dev); if(ip == NULL) { iput(u.u_pdir); return(NULL); } ip->i_flag |= IACC|IUPD|ICHG; if((mode&IFMT) == 0) mode |= IFREG; ip->i_mode = mode & ~u.u_cmask; ip->i_nlink = 1; ip->i_uid = u.u_uid; ip->i_gid = u.u_gid; #ifdef UCB_NODUPS /* * Make sure inode goes to disk before directory entry. */ iupdat(ip, &time, &time, 1); #endif UCB_NODUPS wdir(ip); return(ip); } /* * Write a directory entry with * parameters left as side effects * to a call to namei. */ wdir(ip) struct inode *ip; { if (u.u_pdir->i_nlink <= 0) { u.u_error = ENOTDIR; goto out; } u.u_dent.d_ino = ip->i_number; bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ); u.u_count = sizeof(struct direct); u.u_segflg = 1; u.u_base = (caddr_t)&u.u_dent; writei(u.u_pdir); #ifdef UCB_QUOTAS /* * Copy quota for new file */ if (!u.u_error) qcopy(u.u_pdir, ip); #endif UCB_QUOTAS out: iput(u.u_pdir); }