1 /* ffs_inode.c 4.11 82/06/07 */ 2 3 /* merged into kernel: @(#)iget.c 2.2 4/8/82 */ 4 5 #include "../h/param.h" 6 #include "../h/systm.h" 7 #include "../h/mount.h" 8 #include "../h/dir.h" 9 #include "../h/user.h" 10 #include "../h/inode.h" 11 #include "../h/fs.h" 12 #include "../h/conf.h" 13 #include "../h/buf.h" 14 #include "../h/inline.h" 15 16 #define INOHSZ 63 17 #define INOHASH(dev,ino) (((dev)+(ino))%INOHSZ) 18 short inohash[INOHSZ]; 19 short ifreel; 20 21 /* 22 * Initialize hash links for inodes 23 * and build inode free list. 24 */ 25 ihinit() 26 { 27 register int i; 28 register struct inode *ip = inode; 29 30 ifreel = 0; 31 for (i = 0; i < ninode-1; i++, ip++) 32 ip->i_hlink = i+1; 33 ip->i_hlink = -1; 34 for (i = 0; i < INOHSZ; i++) 35 inohash[i] = -1; 36 } 37 38 /* 39 * Look up an inode by device,inumber. 40 * If it is in core (in the inode structure), 41 * honor the locking protocol. 42 * If it is not in core, read it in from the 43 * specified device. 44 * If the inode is mounted on, perform 45 * the indicated indirection. 46 * In all cases, a pointer to a locked 47 * inode structure is returned. 48 * 49 * panic: no imt -- if the mounted file 50 * system is not in the mount table. 51 * "cannot happen" 52 */ 53 struct inode * 54 iget(dev, fs, ino) 55 dev_t dev; 56 register struct fs *fs; 57 ino_t ino; 58 { 59 register struct inode *ip; 60 register struct mount *mp; 61 register struct buf *bp; 62 register struct dinode *dp; 63 register int slot; 64 65 loop: 66 if (getfs(dev) != fs) 67 panic("iget: bad fs"); 68 slot = INOHASH(dev, ino); 69 ip = &inode[inohash[slot]]; 70 while (ip != &inode[-1]) { 71 if (ino == ip->i_number && dev == ip->i_dev) { 72 if ((ip->i_flag&ILOCK) != 0) { 73 ip->i_flag |= IWANT; 74 sleep((caddr_t)ip, PINOD); 75 goto loop; 76 } 77 if ((ip->i_flag&IMOUNT) != 0) { 78 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 79 if (mp->m_inodp == ip) { 80 dev = mp->m_dev; 81 fs = mp->m_bufp->b_un.b_fs; 82 ino = ROOTINO; 83 goto loop; 84 } 85 panic("no imt"); 86 } 87 ip->i_count++; 88 ip->i_flag |= ILOCK; 89 return(ip); 90 } 91 ip = &inode[ip->i_hlink]; 92 } 93 if (ifreel < 0) { 94 tablefull("inode"); 95 u.u_error = ENFILE; 96 return(NULL); 97 } 98 ip = &inode[ifreel]; 99 ifreel = ip->i_hlink; 100 ip->i_hlink = inohash[slot]; 101 inohash[slot] = ip - inode; 102 ip->i_dev = dev; 103 ip->i_fs = fs; 104 ip->i_number = ino; 105 ip->i_flag = ILOCK; 106 ip->i_count++; 107 ip->i_lastr = 0; 108 bp = bread(dev, fsbtodb(fs, itod(fs, ino)), fs->fs_bsize); 109 /* 110 * Check I/O errors 111 */ 112 if ((bp->b_flags&B_ERROR) != 0) { 113 brelse(bp); 114 iput(ip); 115 return(NULL); 116 } 117 dp = bp->b_un.b_dino; 118 dp += itoo(fs, ino); 119 ip->i_ic = dp->di_ic; 120 brelse(bp); 121 return (ip); 122 } 123 124 /* 125 * Decrement reference count of 126 * an inode structure. 127 * On the last reference, 128 * write the inode out and if necessary, 129 * truncate and deallocate the file. 130 */ 131 iput(ip) 132 register struct inode *ip; 133 { 134 135 if ((ip->i_flag & ILOCK) == 0) 136 panic("iput"); 137 iunlock(ip); 138 irele(ip); 139 } 140 141 irele(ip) 142 register struct inode *ip; 143 { 144 register int i, x; 145 register struct inode *jp; 146 int mode; 147 148 if (ip->i_flag & ILOCK) 149 panic("irele"); 150 if (ip->i_count == 1) { 151 ip->i_flag |= ILOCK; 152 if (ip->i_nlink <= 0) { 153 itrunc(ip); 154 mode = ip->i_mode; 155 ip->i_mode = 0; 156 ip->i_flag |= IUPD|ICHG; 157 ifree(ip, ip->i_number, mode); 158 } 159 IUPDAT(ip, &time, &time, 0); 160 iunlock(ip); 161 i = INOHASH(ip->i_dev, ip->i_number); 162 x = ip - inode; 163 if (inohash[i] == x) { 164 inohash[i] = ip->i_hlink; 165 } else { 166 for (jp = &inode[inohash[i]]; jp != &inode[-1]; 167 jp = &inode[jp->i_hlink]) 168 if (jp->i_hlink == x) { 169 jp->i_hlink = ip->i_hlink; 170 goto done; 171 } 172 panic("iput"); 173 } 174 done: 175 ip->i_hlink = ifreel; 176 ifreel = x; 177 ip->i_flag = 0; 178 ip->i_number = 0; 179 } 180 ip->i_count--; 181 } 182 183 /* 184 * Check accessed and update flags on 185 * an inode structure. 186 * If any is on, update the inode 187 * with the current time. 188 * If waitfor is given, then must insure 189 * i/o order so wait for write to complete. 190 */ 191 iupdat(ip, ta, tm, waitfor) 192 register struct inode *ip; 193 time_t *ta, *tm; 194 int waitfor; 195 { 196 register struct buf *bp; 197 struct dinode *dp; 198 register struct fs *fp; 199 200 fp = ip->i_fs; 201 if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) { 202 if (fp->fs_ronly) 203 return; 204 bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 205 fp->fs_bsize); 206 if (bp->b_flags & B_ERROR) { 207 brelse(bp); 208 return; 209 } 210 if (ip->i_flag&IACC) 211 ip->i_atime = *ta; 212 if (ip->i_flag&IUPD) 213 ip->i_mtime = *tm; 214 if (ip->i_flag&ICHG) 215 ip->i_ctime = time; 216 ip->i_flag &= ~(IUPD|IACC|ICHG); 217 dp = bp->b_un.b_dino + itoo(fp, ip->i_number); 218 dp->di_ic = ip->i_ic; 219 if (waitfor) 220 bwrite(bp); 221 else 222 bdwrite(bp); 223 } 224 } 225 226 /* 227 * Free all the disk blocks associated 228 * with the specified inode structure. 229 * The blocks of the file are removed 230 * in reverse order. This FILO 231 * algorithm will tend to maintain 232 * a contiguous free list much longer 233 * than FIFO. 234 */ 235 itrunc(ip) 236 register struct inode *ip; 237 { 238 register i; 239 dev_t dev; 240 daddr_t bn; 241 struct inode itmp; 242 register struct fs *fs; 243 244 i = ip->i_mode & IFMT; 245 if (i != IFREG && i != IFDIR && i != IFLNK) 246 return; 247 /* 248 * Clean inode on disk before freeing blocks 249 * to insure no duplicates if system crashes. 250 */ 251 itmp = *ip; 252 itmp.i_size = 0; 253 for (i = 0; i < NDADDR; i++) 254 itmp.i_db[i] = 0; 255 for (i = 0; i < NIADDR; i++) 256 itmp.i_ib[i] = 0; 257 itmp.i_flag |= ICHG|IUPD; 258 iupdat(&itmp, &time, &time, 1); 259 ip->i_flag &= ~(IUPD|IACC|ICHG); 260 261 /* 262 * Now return blocks to free list... if machine 263 * crashes, they will be harmless MISSING blocks. 264 */ 265 dev = ip->i_dev; 266 fs = ip->i_fs; 267 /* 268 * release double indirect block first 269 */ 270 bn = ip->i_ib[NIADDR-1]; 271 if (bn != (daddr_t)0) { 272 ip->i_ib[NIADDR - 1] = (daddr_t)0; 273 tloop(ip, bn, 1); 274 } 275 /* 276 * release single indirect blocks second 277 */ 278 for (i = NIADDR - 2; i >= 0; i--) { 279 bn = ip->i_ib[i]; 280 if (bn != (daddr_t)0) { 281 ip->i_ib[i] = (daddr_t)0; 282 tloop(ip, bn, 0); 283 } 284 } 285 /* 286 * finally release direct blocks 287 */ 288 for (i = NDADDR - 1; i>=0; i--) { 289 bn = ip->i_db[i]; 290 if (bn == (daddr_t)0) 291 continue; 292 ip->i_db[i] = (daddr_t)0; 293 fre(ip, bn, (off_t)blksize(fs, ip, i)); 294 } 295 ip->i_size = 0; 296 /* 297 * Inode was written and flags updated above. 298 * No need to modify flags here. 299 */ 300 } 301 302 tloop(ip, bn, indflg) 303 register struct inode *ip; 304 daddr_t bn; 305 int indflg; 306 { 307 register i; 308 register struct buf *bp; 309 register daddr_t *bap; 310 register struct fs *fs; 311 daddr_t nb; 312 313 bp = NULL; 314 fs = ip->i_fs; 315 for (i = NINDIR(fs) - 1; i >= 0; i--) { 316 if (bp == NULL) { 317 bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize); 318 if (bp->b_flags & B_ERROR) { 319 brelse(bp); 320 return; 321 } 322 bap = bp->b_un.b_daddr; 323 } 324 nb = bap[i]; 325 if (nb == (daddr_t)0) 326 continue; 327 if (indflg) 328 tloop(ip, nb, 0); 329 else 330 fre(ip, nb, fs->fs_bsize); 331 } 332 if (bp != NULL) 333 brelse(bp); 334 fre(ip, bn, fs->fs_bsize); 335 } 336 337 /* 338 * Make a new file. 339 */ 340 struct inode * 341 maknode(mode) 342 int mode; 343 { 344 register struct inode *ip; 345 ino_t ipref; 346 347 if ((mode & IFMT) == IFDIR) 348 ipref = dirpref(u.u_pdir->i_fs); 349 else 350 ipref = u.u_pdir->i_number; 351 ip = ialloc(u.u_pdir, ipref, mode); 352 if (ip == NULL) { 353 iput(u.u_pdir); 354 return(NULL); 355 } 356 ip->i_flag |= IACC|IUPD|ICHG; 357 if ((mode & IFMT) == 0) 358 mode |= IFREG; 359 ip->i_mode = mode & ~u.u_cmask; 360 ip->i_nlink = 1; 361 ip->i_uid = u.u_uid; 362 ip->i_gid = u.u_pdir->i_gid; 363 364 /* 365 * Make sure inode goes to disk before directory entry. 366 */ 367 iupdat(ip, &time, &time, 1); 368 wdir(ip); 369 if (u.u_error) { 370 /* 371 * write error occurred trying to update directory 372 * so must deallocate the inode 373 */ 374 ip->i_nlink = 0; 375 ip->i_flag |= ICHG; 376 iput(ip); 377 return(NULL); 378 } 379 return(ip); 380 } 381 382 /* 383 * Write a directory entry with 384 * parameters left as side effects 385 * to a call to namei. 386 */ 387 wdir(ip) 388 struct inode *ip; 389 { 390 register struct direct *dp, *ndp; 391 struct fs *fs; 392 struct buf *bp; 393 int lbn, bn, base; 394 int loc, dsize, spccnt, newsize; 395 char *dirbuf; 396 397 u.u_dent.d_ino = ip->i_number; 398 u.u_segflg = 1; 399 newsize = DIRSIZ(&u.u_dent); 400 /* 401 * if u.u_count == 0, a new directory block must be allocated. 402 */ 403 if (u.u_count == 0) { 404 u.u_dent.d_reclen = DIRBLKSIZ; 405 u.u_count = newsize; 406 u.u_base = (caddr_t)&u.u_dent; 407 writei(u.u_pdir); 408 iput(u.u_pdir); 409 return; 410 } 411 /* 412 * must read in an existing directory block 413 * to prepare to place the new entry into it. 414 */ 415 fs = u.u_pdir->i_fs; 416 lbn = lblkno(fs, u.u_offset); 417 base = blkoff(fs, u.u_offset); 418 bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count)); 419 if (u.u_offset + u.u_count > u.u_pdir->i_size) 420 u.u_pdir->i_size = u.u_offset + u.u_count; 421 bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn)); 422 if (bp->b_flags & B_ERROR) { 423 brelse(bp); 424 return; 425 } 426 dirbuf = bp->b_un.b_addr + base; 427 dp = (struct direct *)dirbuf; 428 dsize = DIRSIZ(dp); 429 spccnt = dp->d_reclen - dsize; 430 /* 431 * if there is insufficient room to make an entry at this point 432 * namei insures that compacting from u.u_offset for u.u_count 433 * bytes will provide the necessary space. 434 */ 435 for (loc = dp->d_reclen; loc < u.u_count; ) { 436 ndp = (struct direct *)(dirbuf + loc); 437 if (dp->d_ino == 0) { 438 spccnt += dsize; 439 } else { 440 dp->d_reclen = dsize; 441 dp = (struct direct *)((char *)dp + dsize); 442 } 443 dsize = DIRSIZ(ndp); 444 spccnt += ndp->d_reclen - dsize; 445 loc += ndp->d_reclen; 446 bcopy(ndp, dp, dsize); 447 } 448 /* 449 * Update the pointer fields in the previous entry (if any), 450 * copy in the new entry, and write out the block. 451 */ 452 if (dp->d_ino == 0) { 453 if (spccnt + dsize < newsize) 454 panic("wdir: compact failed"); 455 u.u_dent.d_reclen = spccnt + dsize; 456 } else { 457 if (spccnt < newsize) 458 panic("wdir: compact failed"); 459 u.u_dent.d_reclen = spccnt; 460 dp->d_reclen = dsize; 461 dp = (struct direct *)((char *)dp + dsize); 462 } 463 bcopy(&u.u_dent, dp, newsize); 464 bwrite(bp); 465 u.u_pdir->i_flag |= IUPD|ICHG; 466 iput(u.u_pdir); 467 } 468 469 #ifdef ilock 470 #undef ilock 471 #endif 472 #ifdef iunlock 473 #undef iunlock 474 #endif 475 /* 476 * Lock an inode. If its already locked, set the WANT bit and sleep. 477 */ 478 ilock(ip) 479 register struct inode *ip; 480 { 481 482 while (ip->i_flag&ILOCK) { 483 ip->i_flag |= IWANT; 484 sleep((caddr_t)ip, PINOD); 485 } 486 ip->i_flag |= ILOCK; 487 } 488 489 /* 490 * Unlock an inode. If WANT bit is on, wakeup. 491 */ 492 iunlock(ip) 493 register struct inode *ip; 494 { 495 496 ip->i_flag &= ~ILOCK; 497 if (ip->i_flag&IWANT) { 498 ip->i_flag &= ~IWANT; 499 wakeup((caddr_t)ip); 500 } 501 } 502