1 /* vfs_cluster.c 3.2 10/14/12 */ 2 3 int distrust = 1; /* TEST */ 4 #include "../h/param.h" 5 #include "../h/systm.h" 6 #include "../h/dir.h" 7 #include "../h/user.h" 8 #include "../h/buf.h" 9 #include "../h/conf.h" 10 #include "../h/proc.h" 11 #include "../h/seg.h" 12 #include "../h/pte.h" 13 #include "../h/vm.h" 14 15 /* 16 * The following several routines allocate and free 17 * buffers with various side effects. In general the 18 * arguments to an allocate routine are a device and 19 * a block number, and the value is a pointer to 20 * to the buffer header; the buffer is marked "busy" 21 * so that no one else can touch it. If the block was 22 * already in core, no I/O need be done; if it is 23 * already busy, the process waits until it becomes free. 24 * The following routines allocate a buffer: 25 * getblk 26 * bread 27 * breada 28 * baddr (if it is incore) 29 * Eventually the buffer must be released, possibly with the 30 * side effect of writing it out, by using one of 31 * bwrite 32 * bdwrite 33 * bawrite 34 * brelse 35 */ 36 37 #define BUFHSZ 63 38 #define BUFHASH(blkno) (blkno % BUFHSZ) 39 short bufhash[BUFHSZ]; 40 41 /* 42 * Initialize hash links for buffers. 43 */ 44 bhinit() 45 { 46 register int i; 47 48 for (i = 0; i < BUFHSZ; i++) 49 bufhash[i] = -1; 50 } 51 52 /* #define DISKMON 1 */ 53 54 #ifdef DISKMON 55 struct { 56 int nbuf; 57 long nread; 58 long nreada; 59 long ncache; 60 long nwrite; 61 long bufcount[NBUF]; 62 } io_info; 63 #endif 64 65 /* 66 * Swap IO headers - 67 * They contain the necessary information for the swap I/O. 68 * At any given time, a swap header can be in three 69 * different lists. When free it is in the free list, 70 * when allocated and the I/O queued, it is on the swap 71 * device list, and finally, if the operation was a dirty 72 * page push, when the I/O completes, it is inserted 73 * in a list of cleaned pages to be processed by the pageout daemon. 74 */ 75 struct buf swbuf[NSWBUF]; 76 short swsize[NSWBUF]; /* CAN WE JUST USE B_BCOUNT? */ 77 int swpf[NSWBUF]; 78 79 80 #ifdef FASTVAX 81 #define notavail(bp) \ 82 { \ 83 int s = spl6(); \ 84 (bp)->av_back->av_forw = (bp)->av_forw; \ 85 (bp)->av_forw->av_back = (bp)->av_back; \ 86 (bp)->b_flags |= B_BUSY; \ 87 splx(s); \ 88 } 89 #endif 90 91 /* 92 * Read in (if necessary) the block and return a buffer pointer. 93 */ 94 struct buf * 95 bread(dev, blkno) 96 dev_t dev; 97 daddr_t blkno; 98 { 99 register struct buf *bp; 100 101 bp = getblk(dev, blkno); 102 if (bp->b_flags&B_DONE) { 103 #ifdef DISKMON 104 io_info.ncache++; 105 #endif 106 return(bp); 107 } 108 bp->b_flags |= B_READ; 109 bp->b_bcount = BSIZE; 110 (*bdevsw[major(dev)].d_strategy)(bp); 111 #ifdef DISKMON 112 io_info.nread++; 113 #endif 114 u.u_vm.vm_inblk++; /* pay for read */ 115 iowait(bp); 116 return(bp); 117 } 118 119 /* 120 * Read in the block, like bread, but also start I/O on the 121 * read-ahead block (which is not allocated to the caller) 122 */ 123 struct buf * 124 breada(dev, blkno, rablkno) 125 dev_t dev; 126 daddr_t blkno, rablkno; 127 { 128 register struct buf *bp, *rabp; 129 130 bp = NULL; 131 if (!incore(dev, blkno)) { 132 bp = getblk(dev, blkno); 133 if ((bp->b_flags&B_DONE) == 0) { 134 bp->b_flags |= B_READ; 135 bp->b_bcount = BSIZE; 136 (*bdevsw[major(dev)].d_strategy)(bp); 137 #ifdef DISKMON 138 io_info.nread++; 139 #endif 140 u.u_vm.vm_inblk++; /* pay for read */ 141 } 142 } 143 if (rablkno && !incore(dev, rablkno)) { 144 rabp = getblk(dev, rablkno); 145 if (rabp->b_flags & B_DONE) 146 brelse(rabp); 147 else { 148 rabp->b_flags |= B_READ|B_ASYNC; 149 rabp->b_bcount = BSIZE; 150 (*bdevsw[major(dev)].d_strategy)(rabp); 151 #ifdef DISKMON 152 io_info.nreada++; 153 #endif 154 u.u_vm.vm_inblk++; /* pay in advance */ 155 } 156 } 157 if(bp == NULL) 158 return(bread(dev, blkno)); 159 iowait(bp); 160 return(bp); 161 } 162 163 /* 164 * Write the buffer, waiting for completion. 165 * Then release the buffer. 166 */ 167 bwrite(bp) 168 register struct buf *bp; 169 { 170 register flag; 171 172 flag = bp->b_flags; 173 bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI | B_AGE); 174 bp->b_bcount = BSIZE; 175 #ifdef DISKMON 176 io_info.nwrite++; 177 #endif 178 if ((flag&B_DELWRI) == 0) 179 u.u_vm.vm_oublk++; /* noone paid yet */ 180 (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 181 if ((flag&B_ASYNC) == 0) { 182 iowait(bp); 183 brelse(bp); 184 } else if (flag & B_DELWRI) 185 bp->b_flags |= B_AGE; 186 else 187 geterror(bp); 188 } 189 190 /* 191 * Release the buffer, marking it so that if it is grabbed 192 * for another purpose it will be written out before being 193 * given up (e.g. when writing a partial block where it is 194 * assumed that another write for the same block will soon follow). 195 * This can't be done for magtape, since writes must be done 196 * in the same order as requested. 197 */ 198 bdwrite(bp) 199 register struct buf *bp; 200 { 201 register struct buf *dp; 202 203 if ((bp->b_flags&B_DELWRI) == 0) 204 u.u_vm.vm_oublk++; /* noone paid yet */ 205 dp = bdevsw[major(bp->b_dev)].d_tab; 206 if(dp->b_flags & B_TAPE) 207 bawrite(bp); 208 else { 209 bp->b_flags |= B_DELWRI | B_DONE; 210 brelse(bp); 211 } 212 } 213 214 /* 215 * Release the buffer, start I/O on it, but don't wait for completion. 216 */ 217 bawrite(bp) 218 register struct buf *bp; 219 { 220 221 bp->b_flags |= B_ASYNC; 222 bwrite(bp); 223 } 224 225 /* 226 * release the buffer, with no I/O implied. 227 */ 228 brelse(bp) 229 register struct buf *bp; 230 { 231 register struct buf **backp; 232 register s; 233 234 if (bp->b_flags&B_WANTED) 235 wakeup((caddr_t)bp); 236 if (bfreelist.b_flags&B_WANTED) { 237 bfreelist.b_flags &= ~B_WANTED; 238 wakeup((caddr_t)&bfreelist); 239 } 240 if ((bp->b_flags&B_ERROR) && bp->b_dev != NODEV) { 241 bunhash(bp); 242 bp->b_dev = NODEV; /* no assoc. on error */ 243 } 244 s = spl6(); 245 if(bp->b_flags & (B_AGE|B_ERROR)) { 246 backp = &bfreelist.av_forw; 247 (*backp)->av_back = bp; 248 bp->av_forw = *backp; 249 *backp = bp; 250 bp->av_back = &bfreelist; 251 } else { 252 backp = &bfreelist.av_back; 253 (*backp)->av_forw = bp; 254 bp->av_back = *backp; 255 *backp = bp; 256 bp->av_forw = &bfreelist; 257 } 258 bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE); 259 splx(s); 260 } 261 262 /* HASHING IS A GUN LIKE CHANGE, THIS IS THE SAFETY */ 263 struct buf * 264 oincore(dev, blkno) 265 dev_t dev; 266 daddr_t blkno; 267 { 268 register struct buf *bp; 269 register struct buf *dp; 270 register int dblkno = fsbtodb(blkno); 271 272 dp = bdevsw[major(dev)].d_tab; 273 for (bp=dp->b_forw; bp != dp; bp = bp->b_forw) 274 if (bp->b_blkno==dblkno && bp->b_dev==dev && 275 bp >= buf && bp < &buf[NBUF]) 276 return (bp); 277 return ((struct buf *)0); 278 } 279 280 /* 281 * See if the block is associated with some buffer 282 * (mainly to avoid getting hung up on a wait in breada) 283 */ 284 incore(dev, blkno) 285 dev_t dev; 286 daddr_t blkno; 287 { 288 register struct buf *bp; 289 register int dblkno = fsbtodb(blkno); 290 291 for (bp = &buf[bufhash[BUFHASH(blkno)]]; bp != &buf[-1]; 292 bp = &buf[bp->b_hlink]) 293 if (bp->b_blkno == dblkno && bp->b_dev == dev) { 294 if (distrust) 295 if (oincore(dev, blkno) != bp) /* TEST */ 296 panic("incore 1"); /* TEST */ 297 return (1); 298 } 299 if (distrust) 300 if (oincore(dev, blkno)) /* TEST */ 301 panic("incore 2"); /* TEST */ 302 return (0); 303 } 304 305 struct buf * 306 baddr(dev, blkno) 307 dev_t dev; 308 daddr_t blkno; 309 { 310 311 if (incore(dev, blkno)) 312 return (bread(dev, blkno)); 313 return (0); 314 } 315 316 /* 317 * Assign a buffer for the given block. If the appropriate 318 * block is already associated, return it; otherwise search 319 * for the oldest non-busy buffer and reassign it. 320 */ 321 struct buf * 322 getblk(dev, blkno) 323 dev_t dev; 324 daddr_t blkno; 325 { 326 register struct buf *bp, *dp, *ep; 327 register int i, x; 328 register int dblkno = fsbtodb(blkno); 329 330 loop: 331 VOID spl0(); 332 for (bp = &buf[bufhash[BUFHASH(blkno)]]; bp != &buf[-1]; 333 bp = &buf[bp->b_hlink]) { 334 if (bp->b_blkno != dblkno || bp->b_dev != dev) 335 continue; 336 if (distrust) 337 if (bp != oincore(dev, blkno)) /* TEST */ 338 panic("getblk 1"); /* TEST */ 339 VOID spl6(); 340 if (bp->b_flags&B_BUSY) { 341 bp->b_flags |= B_WANTED; 342 sleep((caddr_t)bp, PRIBIO+1); 343 goto loop; 344 } 345 VOID spl0(); 346 #ifdef DISKMON 347 i = 0; 348 dp = bp->av_forw; 349 while (dp != &bfreelist) { 350 i++; 351 dp = dp->av_forw; 352 } 353 if (i<NBUF) 354 io_info.bufcount[i]++; 355 #endif 356 notavail(bp); 357 bp->b_flags |= B_CACHE; 358 return(bp); 359 } 360 if (distrust) 361 if (oincore(dev, blkno)) /* TEST */ 362 panic("getblk 2"); /* TEST */ 363 if (major(dev) >= nblkdev) 364 panic("blkdev"); 365 dp = bdevsw[major(dev)].d_tab; 366 if (dp == NULL) 367 panic("devtab"); 368 VOID spl6(); 369 if (bfreelist.av_forw == &bfreelist) { 370 bfreelist.b_flags |= B_WANTED; 371 sleep((caddr_t)&bfreelist, PRIBIO+1); 372 goto loop; 373 } 374 spl0(); 375 bp = bfreelist.av_forw; 376 notavail(bp); 377 if (bp->b_flags & B_DELWRI) { 378 bp->b_flags |= B_ASYNC; 379 bwrite(bp); 380 goto loop; 381 } 382 if (bp->b_dev == NODEV) 383 goto done; 384 /* INLINE EXPANSION OF bunhash(bp) */ 385 i = BUFHASH(dbtofsb(bp->b_blkno)); 386 x = bp - buf; 387 if (bufhash[i] == x) { 388 bufhash[i] = bp->b_hlink; 389 } else { 390 for (ep = &buf[bufhash[i]]; ep != &buf[-1]; 391 ep = &buf[ep->b_hlink]) 392 if (ep->b_hlink == x) { 393 ep->b_hlink = bp->b_hlink; 394 goto done; 395 } 396 panic("getblk"); 397 } 398 done: 399 /* END INLINE EXPANSION */ 400 bp->b_flags = B_BUSY; 401 bp->b_back->b_forw = bp->b_forw; 402 bp->b_forw->b_back = bp->b_back; 403 bp->b_forw = dp->b_forw; 404 bp->b_back = dp; 405 dp->b_forw->b_back = bp; 406 dp->b_forw = bp; 407 bp->b_dev = dev; 408 bp->b_blkno = dblkno; 409 i = BUFHASH(blkno); 410 bp->b_hlink = bufhash[i]; 411 bufhash[i] = bp - buf; 412 return(bp); 413 } 414 415 /* 416 * get an empty block, 417 * not assigned to any particular device 418 */ 419 struct buf * 420 geteblk() 421 { 422 register struct buf *bp, *dp, *ep; 423 register int i, x; 424 425 loop: 426 VOID spl6(); 427 while (bfreelist.av_forw == &bfreelist) { 428 bfreelist.b_flags |= B_WANTED; 429 sleep((caddr_t)&bfreelist, PRIBIO+1); 430 } 431 VOID spl0(); 432 dp = &bfreelist; 433 bp = bfreelist.av_forw; 434 notavail(bp); 435 if (bp->b_flags & B_DELWRI) { 436 bp->b_flags |= B_ASYNC; 437 bwrite(bp); 438 goto loop; 439 } 440 if (bp->b_dev != NODEV) 441 bunhash(bp); 442 bp->b_flags = B_BUSY; 443 bp->b_back->b_forw = bp->b_forw; 444 bp->b_forw->b_back = bp->b_back; 445 bp->b_forw = dp->b_forw; 446 bp->b_back = dp; 447 dp->b_forw->b_back = bp; 448 dp->b_forw = bp; 449 bp->b_dev = (dev_t)NODEV; 450 bp->b_hlink = -1; 451 return(bp); 452 } 453 454 bunhash(bp) 455 register struct buf *bp; 456 { 457 register struct buf *ep; 458 register int i, x; 459 460 if (bp->b_dev == NODEV) 461 return; 462 i = BUFHASH(dbtofsb(bp->b_blkno)); 463 x = bp - buf; 464 if (bufhash[i] == x) { 465 bufhash[i] = bp->b_hlink; 466 return; 467 } 468 for (ep = &buf[bufhash[i]]; ep != &buf[-1]; 469 ep = &buf[ep->b_hlink]) 470 if (ep->b_hlink == x) { 471 ep->b_hlink = bp->b_hlink; 472 return; 473 } 474 panic("bunhash"); 475 } 476 477 /* 478 * Wait for I/O completion on the buffer; return errors 479 * to the user. 480 */ 481 iowait(bp) 482 register struct buf *bp; 483 { 484 485 VOID spl6(); 486 while ((bp->b_flags&B_DONE)==0) 487 sleep((caddr_t)bp, PRIBIO); 488 VOID spl0(); 489 geterror(bp); 490 } 491 492 #ifndef FASTVAX 493 /* 494 * Unlink a buffer from the available list and mark it busy. 495 * (internal interface) 496 */ 497 notavail(bp) 498 register struct buf *bp; 499 { 500 register s; 501 502 s = spl6(); 503 bp->av_back->av_forw = bp->av_forw; 504 bp->av_forw->av_back = bp->av_back; 505 bp->b_flags |= B_BUSY; 506 splx(s); 507 } 508 #endif 509 510 /* 511 * Mark I/O complete on a buffer. If the header 512 * indicates a dirty page push completion, the 513 * header is inserted into the ``cleaned'' list 514 * to be processed by the pageout daemon. Otherwise 515 * release it if I/O is asynchronous, and wake 516 * up anyone waiting for it. 517 */ 518 iodone(bp) 519 register struct buf *bp; 520 { 521 register int s; 522 523 bp->b_flags |= B_DONE; 524 if (bp->b_flags & B_DIRTY) { 525 if (bp->b_flags & B_ERROR) 526 panic("IO err in push"); 527 s = spl6(); 528 cnt.v_pgout++; 529 bp->av_forw = bclnlist; 530 bp->b_bcount = swsize[bp - swbuf]; 531 bp->b_pfcent = swpf[bp - swbuf]; 532 bclnlist = bp; 533 if (bswlist.b_flags & B_WANTED) 534 wakeup((caddr_t)&proc[2]); 535 splx(s); 536 } 537 if (bp->b_flags&B_ASYNC) 538 brelse(bp); 539 else { 540 bp->b_flags &= ~B_WANTED; 541 wakeup((caddr_t)bp); 542 } 543 } 544 545 /* 546 * Zero the core associated with a buffer. 547 */ 548 clrbuf(bp) 549 struct buf *bp; 550 { 551 register *p; 552 register c; 553 554 p = bp->b_un.b_words; 555 c = BSIZE/sizeof(int); 556 do 557 *p++ = 0; 558 while (--c); 559 bp->b_resid = 0; 560 } 561 562 /* 563 * swap I/O - 564 * 565 * If the flag indicates a dirty page push initiated 566 * by the pageout daemon, we map the page into the i th 567 * virtual page of process 2 (the daemon itself) where i is 568 * the index of the swap header that has been allocated. 569 * We simply initialize the header and queue the I/O but 570 * do not wait for completion. When the I/O completes, 571 * iodone() will link the header to a list of cleaned 572 * pages to be processed by the pageout daemon. 573 */ 574 swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent) 575 struct proc *p; 576 swblk_t dblkno; 577 caddr_t addr; 578 int flag, nbytes; 579 dev_t dev; 580 unsigned pfcent; 581 { 582 register struct buf *bp; 583 register int c; 584 int p2dp; 585 register struct pte *dpte, *vpte; 586 587 VOID spl6(); 588 while (bswlist.av_forw == NULL) { 589 bswlist.b_flags |= B_WANTED; 590 sleep((caddr_t)&bswlist, PSWP+1); 591 } 592 bp = bswlist.av_forw; 593 bswlist.av_forw = bp->av_forw; 594 VOID spl0(); 595 596 bp->b_flags = B_BUSY | B_PHYS | rdflg | flag; 597 if ((bp->b_flags & (B_DIRTY|B_PGIN)) == 0) 598 if (rdflg == B_READ) 599 sum.v_pswpin += btoc(nbytes); 600 else 601 sum.v_pswpout += btoc(nbytes); 602 bp->b_proc = p; 603 if (flag & B_DIRTY) { 604 p2dp = ((bp - swbuf) * CLSIZE) * KLMAX; 605 dpte = dptopte(&proc[2], p2dp); 606 vpte = vtopte(p, btop(addr)); 607 for (c = 0; c < nbytes; c += NBPG) { 608 if (vpte->pg_pfnum == 0 || vpte->pg_fod) 609 panic("swap bad pte"); 610 *dpte++ = *vpte++; 611 } 612 bp->b_un.b_addr = (caddr_t)ctob(p2dp); 613 } else 614 bp->b_un.b_addr = addr; 615 while (nbytes > 0) { 616 c = imin(ctob(120), nbytes); 617 bp->b_bcount = c; 618 bp->b_blkno = dblkno; 619 bp->b_dev = dev; 620 if (dev == swapdev) 621 bp->b_blkno += swplo; 622 (*bdevsw[major(dev)].d_strategy)(bp); 623 if (flag & B_DIRTY) { 624 if (c < nbytes) 625 panic("big push"); 626 swsize[bp - swbuf] = nbytes; 627 swpf[bp - swbuf] = pfcent; 628 return; 629 } 630 VOID spl6(); 631 while((bp->b_flags&B_DONE)==0) 632 sleep((caddr_t)bp, PSWP); 633 VOID spl0(); 634 bp->b_un.b_addr += c; 635 bp->b_flags &= ~B_DONE; 636 if (bp->b_flags & B_ERROR) { 637 if ((flag & (B_UAREA|B_PAGET)) || rdflg == B_WRITE) 638 panic("hard IO err in swap"); 639 swkill(p, (char *)0); 640 } 641 nbytes -= c; 642 dblkno += btoc(c); 643 } 644 VOID spl6(); 645 bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY); 646 bp->av_forw = bswlist.av_forw; 647 bswlist.av_forw = bp; 648 if (bswlist.b_flags & B_WANTED) { 649 bswlist.b_flags &= ~B_WANTED; 650 wakeup((caddr_t)&bswlist); 651 wakeup((caddr_t)&proc[2]); 652 } 653 VOID spl0(); 654 } 655 656 /* 657 * If rout == 0 then killed on swap error, else 658 * rout is the name of the routine where we ran out of 659 * swap space. 660 */ 661 swkill(p, rout) 662 struct proc *p; 663 char *rout; 664 { 665 666 printf("%d: ", p->p_pid); 667 if (rout) 668 printf("out of swap space in %s\n", rout); 669 else 670 printf("killed on swap error\n"); 671 /* 672 * To be sure no looping (e.g. in vmsched trying to 673 * swap out) mark process locked in core (as though 674 * done by user) after killing it so noone will try 675 * to swap it out. 676 */ 677 psignal(p, SIGKIL); 678 p->p_flag |= SULOCK; 679 } 680 681 /* 682 * make sure all write-behind blocks 683 * on dev (or NODEV for all) 684 * are flushed out. 685 * (from umount and update) 686 */ 687 bflush(dev) 688 dev_t dev; 689 { 690 register struct buf *bp; 691 692 loop: 693 VOID spl6(); 694 for (bp = bfreelist.av_forw; bp != &bfreelist; bp = bp->av_forw) { 695 if (bp->b_flags&B_DELWRI && (dev == NODEV||dev==bp->b_dev)) { 696 bp->b_flags |= B_ASYNC; 697 notavail(bp); 698 bwrite(bp); 699 goto loop; 700 } 701 } 702 VOID spl0(); 703 } 704 705 /* 706 * Raw I/O. The arguments are 707 * The strategy routine for the device 708 * A buffer, which will always be a special buffer 709 * header owned exclusively by the device for this purpose 710 * The device number 711 * Read/write flag 712 * Essentially all the work is computing physical addresses and 713 * validating them. 714 * If the user has the proper access privilidges, the process is 715 * marked 'delayed unlock' and the pages involved in the I/O are 716 * faulted and locked. After the completion of the I/O, the above pages 717 * are unlocked. 718 */ 719 physio(strat, bp, dev, rw, mincnt) 720 int (*strat)(); 721 register struct buf *bp; 722 unsigned (*mincnt)(); 723 { 724 register int c; 725 char *a; 726 727 if (useracc(u.u_base,u.u_count,rw==B_READ?B_WRITE:B_READ) == NULL) { 728 u.u_error = EFAULT; 729 return; 730 } 731 VOID spl6(); 732 while (bp->b_flags&B_BUSY) { 733 bp->b_flags |= B_WANTED; 734 sleep((caddr_t)bp, PRIBIO+1); 735 } 736 bp->b_error = 0; 737 bp->b_proc = u.u_procp; 738 bp->b_un.b_addr = u.u_base; 739 while (u.u_count != 0 && bp->b_error==0) { 740 bp->b_flags = B_BUSY | B_PHYS | rw; 741 bp->b_dev = dev; 742 bp->b_blkno = u.u_offset >> PGSHIFT; 743 bp->b_bcount = u.u_count; 744 (*mincnt)(bp); 745 c = bp->b_bcount; 746 u.u_procp->p_flag |= SPHYSIO; 747 vslock(a = bp->b_un.b_addr, c); 748 (*strat)(bp); 749 VOID spl6(); 750 while ((bp->b_flags&B_DONE) == 0) 751 sleep((caddr_t)bp, PRIBIO); 752 vsunlock(a, c, rw); 753 u.u_procp->p_flag &= ~SPHYSIO; 754 if (bp->b_flags&B_WANTED) 755 wakeup((caddr_t)bp); 756 VOID spl0(); 757 bp->b_un.b_addr += c; 758 u.u_count -= c; 759 u.u_offset += c; 760 } 761 bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS); 762 u.u_count = bp->b_resid; 763 geterror(bp); 764 } 765 766 /*ARGSUSED*/ 767 unsigned 768 minphys(bp) 769 struct buf *bp; 770 { 771 772 if (bp->b_bcount > 60 * 1024) 773 bp->b_bcount = 60 * 1024; 774 } 775 776 /* 777 * Pick up the device's error number and pass it to the user; 778 * if there is an error but the number is 0 set a generalized 779 * code. Actually the latter is always true because devices 780 * don't yet return specific errors. 781 */ 782 geterror(bp) 783 register struct buf *bp; 784 { 785 786 if (bp->b_flags&B_ERROR) 787 if ((u.u_error = bp->b_error)==0) 788 u.u_error = EIO; 789 } 790