1*24Sbill /* lfs_inode.c 3.1 10/14/12 */ 2*24Sbill 3*24Sbill #include "../h/param.h" 4*24Sbill #include "../h/systm.h" 5*24Sbill #include "../h/mount.h" 6*24Sbill #include "../h/dir.h" 7*24Sbill #include "../h/user.h" 8*24Sbill #include "../h/inode.h" 9*24Sbill #include "../h/ino.h" 10*24Sbill #include "../h/filsys.h" 11*24Sbill #include "../h/conf.h" 12*24Sbill #include "../h/buf.h" 13*24Sbill #include "../h/inline.h" 14*24Sbill 15*24Sbill #define INOHSZ 63 16*24Sbill #define INOHASH(dev,ino) (((dev)+(ino))%INOHSZ) 17*24Sbill short inohash[INOHSZ]; 18*24Sbill short ifreel; 19*24Sbill 20*24Sbill /* 21*24Sbill * Initialize hash links for inodes 22*24Sbill * and build inode free list. 23*24Sbill */ 24*24Sbill ihinit() 25*24Sbill { 26*24Sbill register int i; 27*24Sbill 28*24Sbill ifreel = 0; 29*24Sbill for (i = 0; i < NINODE - 1; i++) 30*24Sbill inode[i].i_hlink = i+1; 31*24Sbill inode[NINODE - 1].i_hlink = -1; 32*24Sbill for (i = 0; i < INOHSZ; i++) 33*24Sbill inohash[i] = -1; 34*24Sbill } 35*24Sbill 36*24Sbill /* 37*24Sbill * Find an inode if it is incore. 38*24Sbill * This is the equivalent, for inodes, 39*24Sbill * of ``incore'' in bio.c or ``pfind'' in subr.c. 40*24Sbill */ 41*24Sbill struct inode * 42*24Sbill ifind(dev, ino) 43*24Sbill dev_t dev; 44*24Sbill ino_t ino; 45*24Sbill { 46*24Sbill register struct inode *ip; 47*24Sbill 48*24Sbill for (ip = &inode[inohash[INOHASH(dev,ino)]]; ip != &inode[-1]; 49*24Sbill ip = &inode[ip->i_hlink]) 50*24Sbill if (ino==ip->i_number && dev==ip->i_dev) 51*24Sbill return (ip); 52*24Sbill return ((struct inode *)0); 53*24Sbill } 54*24Sbill 55*24Sbill /* 56*24Sbill * Look up an inode by device,inumber. 57*24Sbill * If it is in core (in the inode structure), 58*24Sbill * honor the locking protocol. 59*24Sbill * If it is not in core, read it in from the 60*24Sbill * specified device. 61*24Sbill * If the inode is mounted on, perform 62*24Sbill * the indicated indirection. 63*24Sbill * In all cases, a pointer to a locked 64*24Sbill * inode structure is returned. 65*24Sbill * 66*24Sbill * printf warning: no inodes -- if the inode 67*24Sbill * structure is full 68*24Sbill * panic: no imt -- if the mounted file 69*24Sbill * system is not in the mount table. 70*24Sbill * "cannot happen" 71*24Sbill */ 72*24Sbill struct inode * 73*24Sbill iget(dev, ino) 74*24Sbill dev_t dev; 75*24Sbill ino_t ino; 76*24Sbill { 77*24Sbill register struct inode *ip; 78*24Sbill register struct mount *mp; 79*24Sbill register struct buf *bp; 80*24Sbill register struct dinode *dp; 81*24Sbill register int slot; 82*24Sbill 83*24Sbill loop: 84*24Sbill slot = INOHASH(dev, ino); 85*24Sbill ip = &inode[inohash[slot]]; 86*24Sbill while (ip != &inode[-1]) { 87*24Sbill if(ino == ip->i_number && dev == ip->i_dev) { 88*24Sbill if((ip->i_flag&ILOCK) != 0) { 89*24Sbill ip->i_flag |= IWANT; 90*24Sbill sleep((caddr_t)ip, PINOD); 91*24Sbill goto loop; 92*24Sbill } 93*24Sbill if((ip->i_flag&IMOUNT) != 0) { 94*24Sbill for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 95*24Sbill if(mp->m_inodp == ip) { 96*24Sbill dev = mp->m_dev; 97*24Sbill ino = ROOTINO; 98*24Sbill goto loop; 99*24Sbill } 100*24Sbill panic("no imt"); 101*24Sbill } 102*24Sbill ip->i_count++; 103*24Sbill ip->i_flag |= ILOCK; 104*24Sbill return(ip); 105*24Sbill } 106*24Sbill ip = &inode[ip->i_hlink]; 107*24Sbill } 108*24Sbill if(ifreel < 0) { 109*24Sbill printf("Inode table overflow\n"); 110*24Sbill u.u_error = ENFILE; 111*24Sbill return(NULL); 112*24Sbill } 113*24Sbill ip = &inode[ifreel]; 114*24Sbill ifreel = ip->i_hlink; 115*24Sbill ip->i_hlink = inohash[slot]; 116*24Sbill inohash[slot] = ip - inode; 117*24Sbill ip->i_dev = dev; 118*24Sbill ip->i_number = ino; 119*24Sbill ip->i_flag = ILOCK; 120*24Sbill ip->i_count++; 121*24Sbill ip->i_un.i_lastr = 0; 122*24Sbill bp = bread(dev, itod(ino)); 123*24Sbill /* 124*24Sbill * Check I/O errors 125*24Sbill */ 126*24Sbill if((bp->b_flags&B_ERROR) != 0) { 127*24Sbill brelse(bp); 128*24Sbill iput(ip); 129*24Sbill return(NULL); 130*24Sbill } 131*24Sbill dp = bp->b_un.b_dino; 132*24Sbill dp += itoo(ino); 133*24Sbill iexpand(ip, dp); 134*24Sbill brelse(bp); 135*24Sbill return(ip); 136*24Sbill } 137*24Sbill 138*24Sbill iexpand(ip, dp) 139*24Sbill register struct inode *ip; 140*24Sbill register struct dinode *dp; 141*24Sbill { 142*24Sbill register char *p1, *p2; 143*24Sbill register int i; 144*24Sbill 145*24Sbill ip->i_mode = dp->di_mode; 146*24Sbill ip->i_nlink = dp->di_nlink; 147*24Sbill ip->i_uid = dp->di_uid; 148*24Sbill ip->i_gid = dp->di_gid; 149*24Sbill ip->i_size = dp->di_size; 150*24Sbill p1 = (char *)ip->i_un.i_addr; 151*24Sbill p2 = (char *)dp->di_addr; 152*24Sbill for(i=0; i<NADDR; i++) { 153*24Sbill *p1++ = *p2++; 154*24Sbill *p1++ = *p2++; 155*24Sbill *p1++ = *p2++; 156*24Sbill *p1++ = 0; 157*24Sbill } 158*24Sbill } 159*24Sbill 160*24Sbill /* 161*24Sbill * Decrement reference count of 162*24Sbill * an inode structure. 163*24Sbill * On the last reference, 164*24Sbill * write the inode out and if necessary, 165*24Sbill * truncate and deallocate the file. 166*24Sbill */ 167*24Sbill iput(ip) 168*24Sbill register struct inode *ip; 169*24Sbill { 170*24Sbill register int i, x; 171*24Sbill register struct inode *jp; 172*24Sbill 173*24Sbill if(ip->i_count == 1) { 174*24Sbill ip->i_flag |= ILOCK; 175*24Sbill if(ip->i_nlink <= 0) { 176*24Sbill itrunc(ip); 177*24Sbill ip->i_mode = 0; 178*24Sbill ip->i_flag |= IUPD|ICHG; 179*24Sbill ifree(ip->i_dev, ip->i_number); 180*24Sbill } 181*24Sbill iupdat(ip, &time, &time); 182*24Sbill prele(ip); 183*24Sbill i = INOHASH(ip->i_dev, ip->i_number); 184*24Sbill x = ip - inode; 185*24Sbill if (inohash[i] == x) { 186*24Sbill inohash[i] = ip->i_hlink; 187*24Sbill } else { 188*24Sbill for (jp = &inode[inohash[i]]; jp != &inode[-1]; 189*24Sbill jp = &inode[jp->i_hlink]) 190*24Sbill if (jp->i_hlink == x) { 191*24Sbill jp->i_hlink = ip->i_hlink; 192*24Sbill goto done; 193*24Sbill } 194*24Sbill panic("iput"); 195*24Sbill } 196*24Sbill done: 197*24Sbill ip->i_hlink = ifreel; 198*24Sbill ifreel = x; 199*24Sbill ip->i_flag = 0; 200*24Sbill ip->i_number = 0; 201*24Sbill } else 202*24Sbill prele(ip); 203*24Sbill ip->i_count--; 204*24Sbill } 205*24Sbill 206*24Sbill /* 207*24Sbill * Check accessed and update flags on 208*24Sbill * an inode structure. 209*24Sbill * If any is on, update the inode 210*24Sbill * with the current time. 211*24Sbill */ 212*24Sbill iupdat(ip, ta, tm) 213*24Sbill register struct inode *ip; 214*24Sbill time_t *ta, *tm; 215*24Sbill { 216*24Sbill register struct buf *bp; 217*24Sbill struct dinode *dp; 218*24Sbill register char *p1, *p2; 219*24Sbill register int i; 220*24Sbill 221*24Sbill if((ip->i_flag&(IUPD|IACC|ICHG)) != 0) { 222*24Sbill if(getfs(ip->i_dev)->s_ronly) 223*24Sbill return; 224*24Sbill bp = bread(ip->i_dev, itod(ip->i_number)); 225*24Sbill if (bp->b_flags & B_ERROR) { 226*24Sbill brelse(bp); 227*24Sbill return; 228*24Sbill } 229*24Sbill dp = bp->b_un.b_dino; 230*24Sbill dp += itoo(ip->i_number); 231*24Sbill dp->di_mode = ip->i_mode; 232*24Sbill dp->di_nlink = ip->i_nlink; 233*24Sbill dp->di_uid = ip->i_uid; 234*24Sbill dp->di_gid = ip->i_gid; 235*24Sbill dp->di_size = ip->i_size; 236*24Sbill p1 = (char *)dp->di_addr; 237*24Sbill p2 = (char *)ip->i_un.i_addr; 238*24Sbill for(i=0; i<NADDR; i++) { 239*24Sbill *p1++ = *p2++; 240*24Sbill *p1++ = *p2++; 241*24Sbill *p1++ = *p2++; 242*24Sbill if(*p2++ != 0 && (ip->i_mode&IFMT)!=IFMPC 243*24Sbill && (ip->i_mode&IFMT)!=IFMPB) 244*24Sbill printf("iaddress > 2^24\n"); 245*24Sbill } 246*24Sbill if(ip->i_flag&IACC) 247*24Sbill dp->di_atime = *ta; 248*24Sbill if(ip->i_flag&IUPD) 249*24Sbill dp->di_mtime = *tm; 250*24Sbill if(ip->i_flag&ICHG) 251*24Sbill dp->di_ctime = time; 252*24Sbill ip->i_flag &= ~(IUPD|IACC|ICHG); 253*24Sbill bdwrite(bp); 254*24Sbill } 255*24Sbill } 256*24Sbill 257*24Sbill /* 258*24Sbill * Free all the disk blocks associated 259*24Sbill * with the specified inode structure. 260*24Sbill * The blocks of the file are removed 261*24Sbill * in reverse order. This FILO 262*24Sbill * algorithm will tend to maintain 263*24Sbill * a contiguous free list much longer 264*24Sbill * than FIFO. 265*24Sbill */ 266*24Sbill itrunc(ip) 267*24Sbill register struct inode *ip; 268*24Sbill { 269*24Sbill register i; 270*24Sbill dev_t dev; 271*24Sbill daddr_t bn; 272*24Sbill 273*24Sbill if (ip->i_vfdcnt) 274*24Sbill panic("itrunc"); 275*24Sbill i = ip->i_mode & IFMT; 276*24Sbill if (i!=IFREG && i!=IFDIR) 277*24Sbill return; 278*24Sbill dev = ip->i_dev; 279*24Sbill for(i=NADDR-1; i>=0; i--) { 280*24Sbill bn = ip->i_un.i_addr[i]; 281*24Sbill if(bn == (daddr_t)0) 282*24Sbill continue; 283*24Sbill ip->i_un.i_addr[i] = (daddr_t)0; 284*24Sbill switch(i) { 285*24Sbill 286*24Sbill default: 287*24Sbill free(dev, bn); 288*24Sbill break; 289*24Sbill 290*24Sbill case NADDR-3: 291*24Sbill tloop(dev, bn, 0, 0); 292*24Sbill break; 293*24Sbill 294*24Sbill case NADDR-2: 295*24Sbill tloop(dev, bn, 1, 0); 296*24Sbill break; 297*24Sbill 298*24Sbill case NADDR-1: 299*24Sbill tloop(dev, bn, 1, 1); 300*24Sbill } 301*24Sbill } 302*24Sbill ip->i_size = 0; 303*24Sbill ip->i_flag |= ICHG|IUPD; 304*24Sbill } 305*24Sbill 306*24Sbill tloop(dev, bn, f1, f2) 307*24Sbill dev_t dev; 308*24Sbill daddr_t bn; 309*24Sbill { 310*24Sbill register i; 311*24Sbill register struct buf *bp; 312*24Sbill register daddr_t *bap; 313*24Sbill daddr_t nb; 314*24Sbill 315*24Sbill bp = NULL; 316*24Sbill for(i=NINDIR-1; i>=0; i--) { 317*24Sbill if(bp == NULL) { 318*24Sbill bp = bread(dev, bn); 319*24Sbill if (bp->b_flags & B_ERROR) { 320*24Sbill brelse(bp); 321*24Sbill return; 322*24Sbill } 323*24Sbill bap = bp->b_un.b_daddr; 324*24Sbill } 325*24Sbill nb = bap[i]; 326*24Sbill if(nb == (daddr_t)0) 327*24Sbill continue; 328*24Sbill if(f1) { 329*24Sbill brelse(bp); 330*24Sbill bp = NULL; 331*24Sbill tloop(dev, nb, f2, 0); 332*24Sbill } else 333*24Sbill free(dev, nb); 334*24Sbill } 335*24Sbill if(bp != NULL) 336*24Sbill brelse(bp); 337*24Sbill free(dev, bn); 338*24Sbill } 339*24Sbill 340*24Sbill /* 341*24Sbill * Make a new file. 342*24Sbill */ 343*24Sbill struct inode * 344*24Sbill maknode(mode) 345*24Sbill { 346*24Sbill register struct inode *ip; 347*24Sbill 348*24Sbill ip = ialloc(u.u_pdir->i_dev); 349*24Sbill if(ip == NULL) { 350*24Sbill iput(u.u_pdir); 351*24Sbill return(NULL); 352*24Sbill } 353*24Sbill ip->i_flag |= IACC|IUPD|ICHG; 354*24Sbill if((mode&IFMT) == 0) 355*24Sbill mode |= IFREG; 356*24Sbill ip->i_mode = mode & ~u.u_cmask; 357*24Sbill ip->i_nlink = 1; 358*24Sbill ip->i_uid = u.u_uid; 359*24Sbill ip->i_gid = u.u_gid; 360*24Sbill wdir(ip); 361*24Sbill return(ip); 362*24Sbill } 363*24Sbill 364*24Sbill /* 365*24Sbill * Write a directory entry with 366*24Sbill * parameters left as side effects 367*24Sbill * to a call to namei. 368*24Sbill */ 369*24Sbill wdir(ip) 370*24Sbill struct inode *ip; 371*24Sbill { 372*24Sbill 373*24Sbill u.u_dent.d_ino = ip->i_number; 374*24Sbill bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ); 375*24Sbill u.u_count = sizeof(struct direct); 376*24Sbill u.u_segflg = 1; 377*24Sbill u.u_base = (caddr_t)&u.u_dent; 378*24Sbill writei(u.u_pdir); 379*24Sbill iput(u.u_pdir); 380*24Sbill } 381