1 /* ffs_inode.c 4.10 82/04/19 */ 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 register int i, x; 135 register struct inode *jp; 136 int mode; 137 138 if (ip->i_count == 1) { 139 ip->i_flag |= ILOCK; 140 if (ip->i_nlink <= 0) { 141 itrunc(ip); 142 mode = ip->i_mode; 143 ip->i_mode = 0; 144 ip->i_flag |= IUPD|ICHG; 145 ifree(ip, ip->i_number, mode); 146 } 147 IUPDAT(ip, &time, &time, 0); 148 irele(ip); 149 i = INOHASH(ip->i_dev, ip->i_number); 150 x = ip - inode; 151 if (inohash[i] == x) { 152 inohash[i] = ip->i_hlink; 153 } else { 154 for (jp = &inode[inohash[i]]; jp != &inode[-1]; 155 jp = &inode[jp->i_hlink]) 156 if (jp->i_hlink == x) { 157 jp->i_hlink = ip->i_hlink; 158 goto done; 159 } 160 panic("iput"); 161 } 162 done: 163 ip->i_hlink = ifreel; 164 ifreel = x; 165 ip->i_flag = 0; 166 ip->i_number = 0; 167 } else 168 irele(ip); 169 ip->i_count--; 170 } 171 172 /* 173 * Check accessed and update flags on 174 * an inode structure. 175 * If any is on, update the inode 176 * with the current time. 177 * If waitfor is given, then must insure 178 * i/o order so wait for write to complete. 179 */ 180 iupdat(ip, ta, tm, waitfor) 181 register struct inode *ip; 182 time_t *ta, *tm; 183 int waitfor; 184 { 185 register struct buf *bp; 186 struct dinode *dp; 187 register struct fs *fp; 188 189 fp = ip->i_fs; 190 if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) { 191 if (fp->fs_ronly) 192 return; 193 bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 194 fp->fs_bsize); 195 if (bp->b_flags & B_ERROR) { 196 brelse(bp); 197 return; 198 } 199 if (ip->i_flag&IACC) 200 ip->i_atime = *ta; 201 if (ip->i_flag&IUPD) 202 ip->i_mtime = *tm; 203 if (ip->i_flag&ICHG) 204 ip->i_ctime = time; 205 ip->i_flag &= ~(IUPD|IACC|ICHG); 206 dp = bp->b_un.b_dino + itoo(fp, ip->i_number); 207 dp->di_ic = ip->i_ic; 208 if (waitfor) 209 bwrite(bp); 210 else 211 bdwrite(bp); 212 } 213 } 214 215 /* 216 * Free all the disk blocks associated 217 * with the specified inode structure. 218 * The blocks of the file are removed 219 * in reverse order. This FILO 220 * algorithm will tend to maintain 221 * a contiguous free list much longer 222 * than FIFO. 223 */ 224 itrunc(ip) 225 register struct inode *ip; 226 { 227 register i; 228 dev_t dev; 229 daddr_t bn; 230 struct inode itmp; 231 register struct fs *fs; 232 233 i = ip->i_mode & IFMT; 234 if (i != IFREG && i != IFDIR && i != IFLNK) 235 return; 236 /* 237 * Clean inode on disk before freeing blocks 238 * to insure no duplicates if system crashes. 239 */ 240 itmp = *ip; 241 itmp.i_size = 0; 242 for (i = 0; i < NDADDR; i++) 243 itmp.i_db[i] = 0; 244 for (i = 0; i < NIADDR; i++) 245 itmp.i_ib[i] = 0; 246 itmp.i_flag |= ICHG|IUPD; 247 iupdat(&itmp, &time, &time, 1); 248 ip->i_flag &= ~(IUPD|IACC|ICHG); 249 250 /* 251 * Now return blocks to free list... if machine 252 * crashes, they will be harmless MISSING blocks. 253 */ 254 dev = ip->i_dev; 255 fs = ip->i_fs; 256 /* 257 * release double indirect block first 258 */ 259 bn = ip->i_ib[NIADDR-1]; 260 if (bn != (daddr_t)0) { 261 ip->i_ib[NIADDR - 1] = (daddr_t)0; 262 tloop(ip, bn, 1); 263 } 264 /* 265 * release single indirect blocks second 266 */ 267 for (i = NIADDR - 2; i >= 0; i--) { 268 bn = ip->i_ib[i]; 269 if (bn != (daddr_t)0) { 270 ip->i_ib[i] = (daddr_t)0; 271 tloop(ip, bn, 0); 272 } 273 } 274 /* 275 * finally release direct blocks 276 */ 277 for (i = NDADDR - 1; i>=0; i--) { 278 bn = ip->i_db[i]; 279 if (bn == (daddr_t)0) 280 continue; 281 ip->i_db[i] = (daddr_t)0; 282 fre(ip, bn, (off_t)blksize(fs, ip, i)); 283 } 284 ip->i_size = 0; 285 /* 286 * Inode was written and flags updated above. 287 * No need to modify flags here. 288 */ 289 } 290 291 tloop(ip, bn, indflg) 292 register struct inode *ip; 293 daddr_t bn; 294 int indflg; 295 { 296 register i; 297 register struct buf *bp; 298 register daddr_t *bap; 299 register struct fs *fs; 300 daddr_t nb; 301 302 bp = NULL; 303 fs = ip->i_fs; 304 for (i = NINDIR(fs) - 1; i >= 0; i--) { 305 if (bp == NULL) { 306 bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize); 307 if (bp->b_flags & B_ERROR) { 308 brelse(bp); 309 return; 310 } 311 bap = bp->b_un.b_daddr; 312 } 313 nb = bap[i]; 314 if (nb == (daddr_t)0) 315 continue; 316 if (indflg) 317 tloop(ip, nb, 0); 318 else 319 fre(ip, nb, fs->fs_bsize); 320 } 321 if (bp != NULL) 322 brelse(bp); 323 fre(ip, bn, fs->fs_bsize); 324 } 325 326 /* 327 * Make a new file. 328 */ 329 struct inode * 330 maknode(mode) 331 int mode; 332 { 333 register struct inode *ip; 334 ino_t ipref; 335 336 if ((mode & IFMT) == IFDIR) 337 ipref = dirpref(u.u_pdir->i_fs); 338 else 339 ipref = u.u_pdir->i_number; 340 ip = ialloc(u.u_pdir, ipref, mode); 341 if (ip == NULL) { 342 iput(u.u_pdir); 343 return(NULL); 344 } 345 ip->i_flag |= IACC|IUPD|ICHG; 346 if ((mode & IFMT) == 0) 347 mode |= IFREG; 348 ip->i_mode = mode & ~u.u_cmask; 349 ip->i_nlink = 1; 350 ip->i_uid = u.u_uid; 351 ip->i_gid = u.u_pdir->i_gid; 352 353 /* 354 * Make sure inode goes to disk before directory entry. 355 */ 356 iupdat(ip, &time, &time, 1); 357 wdir(ip); 358 if (u.u_error) { 359 /* 360 * write error occurred trying to update directory 361 * so must deallocate the inode 362 */ 363 ip->i_nlink = 0; 364 ip->i_flag |= ICHG; 365 iput(ip); 366 return(NULL); 367 } 368 return(ip); 369 } 370 371 /* 372 * Write a directory entry with 373 * parameters left as side effects 374 * to a call to namei. 375 */ 376 wdir(ip) 377 struct inode *ip; 378 { 379 register struct direct *dp, *ndp; 380 struct fs *fs; 381 struct buf *bp; 382 int lbn, bn, base; 383 int loc, dsize, spccnt, newsize; 384 char *dirbuf; 385 386 u.u_dent.d_ino = ip->i_number; 387 u.u_segflg = 1; 388 newsize = DIRSIZ(&u.u_dent); 389 /* 390 * if u.u_count == 0, a new directory block must be allocated. 391 */ 392 if (u.u_count == 0) { 393 u.u_dent.d_reclen = DIRBLKSIZ; 394 u.u_count = newsize; 395 u.u_base = (caddr_t)&u.u_dent; 396 writei(u.u_pdir); 397 iput(u.u_pdir); 398 return; 399 } 400 /* 401 * must read in an existing directory block 402 * to prepare to place the new entry into it. 403 */ 404 fs = u.u_pdir->i_fs; 405 lbn = lblkno(fs, u.u_offset); 406 base = blkoff(fs, u.u_offset); 407 bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count)); 408 if (u.u_offset + u.u_count > u.u_pdir->i_size) 409 u.u_pdir->i_size = u.u_offset + u.u_count; 410 bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn)); 411 if (bp->b_flags & B_ERROR) { 412 brelse(bp); 413 return; 414 } 415 dirbuf = bp->b_un.b_addr + base; 416 dp = (struct direct *)dirbuf; 417 dsize = DIRSIZ(dp); 418 spccnt = dp->d_reclen - dsize; 419 /* 420 * if there is insufficient room to make an entry at this point 421 * namei insures that compacting from u.u_offset for u.u_count 422 * bytes will provide the necessary space. 423 */ 424 for (loc = dp->d_reclen; loc < u.u_count; ) { 425 ndp = (struct direct *)(dirbuf + loc); 426 if (dp->d_ino == 0) { 427 spccnt += dsize; 428 } else { 429 dp->d_reclen = dsize; 430 dp = (struct direct *)((char *)dp + dsize); 431 } 432 dsize = DIRSIZ(ndp); 433 spccnt += ndp->d_reclen - dsize; 434 loc += ndp->d_reclen; 435 bcopy(ndp, dp, dsize); 436 } 437 /* 438 * Update the pointer fields in the previous entry (if any), 439 * copy in the new entry, and write out the block. 440 */ 441 if (dp->d_ino == 0) { 442 if (spccnt + dsize < newsize) 443 panic("wdir: compact failed"); 444 u.u_dent.d_reclen = spccnt + dsize; 445 } else { 446 if (spccnt < newsize) 447 panic("wdir: compact failed"); 448 u.u_dent.d_reclen = spccnt; 449 dp->d_reclen = dsize; 450 dp = (struct direct *)((char *)dp + dsize); 451 } 452 bcopy(&u.u_dent, dp, newsize); 453 bwrite(bp); 454 u.u_pdir->i_flag |= IUPD|ICHG; 455 iput(u.u_pdir); 456 } 457 458 #ifdef ilock 459 #undef ilock 460 #endif 461 #ifdef irele 462 #undef irele 463 #endif 464 /* 465 * Lock an inode. If its already locked, set the WANT bit and sleep. 466 */ 467 ilock(ip) 468 register struct inode *ip; 469 { 470 471 while (ip->i_flag&ILOCK) { 472 ip->i_flag |= IWANT; 473 sleep((caddr_t)ip, PINOD); 474 } 475 ip->i_flag |= ILOCK; 476 } 477 478 /* 479 * Unlock an inode. If WANT bit is on, wakeup. 480 */ 481 irele(ip) 482 register struct inode *ip; 483 { 484 485 ip->i_flag &= ~ILOCK; 486 if (ip->i_flag&IWANT) { 487 ip->i_flag &= ~IWANT; 488 wakeup((caddr_t)ip); 489 } 490 } 491