#include "../h/local.h" #ifdef SCCS_ID static char SCCS_ID [] = "@(#)subr.c 3.6 16:33:33 - 81/12/16 "; #endif SCCS_ID #include "../h/param.h" #include "../h/systm.h" #include "../h/conf.h" #include "../h/inode.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/buf.h" /* * Bmap defines the structure of file system storage * by returning the physical block number on a device given the * inode and the logical block number in a file. * When convenient, it also leaves the physical * block number of the next block of the file in rablock * for use in read-ahead. */ #ifdef V6 bmap(ip, bn) struct inode *ip; int bn; { register *bp, *bap, nb; int *nbp, d, i; d = ip->i_dev; if(bn & ~0377777) { /***/ u.u_error = EFBIG; return(0); } if((ip->i_mode&ILARG) == 0) { /* * small file algorithm */ if((bn & ~7) != 0) { /* * convert small to large */ if ((bp = alloc(d)) == NULL) return(-1); bap = bp->b_un.b_addr; for(i=0; i<8; i++) { *bap++ = ip->i_un.i_addr[i]; ip->i_un.i_addr[i] = 0; } ip->i_un.i_addr[0] = bp->b_blkno; bdwrite(bp); ip->i_mode =| ILARG; goto large; } nb = ip->i_un.i_addr[bn]; if(nb == 0 && (bp = alloc(d)) != NULL) { bdwrite(bp); nb = bp->b_blkno; ip->i_un.i_addr[bn] = nb; ip->i_flag =| IUPD; } rablock = 0; if (bn<7) rablock = ip->i_un.i_addr[bn+1]; return(nb); } /* * large file algorithm */ large: i = bn>>7; /***/ if(i > 7) /***/ i = 7; if((nb=ip->i_un.i_addr[i]) == 0) { ip->i_flag =| IUPD; if ((bp = alloc(d)) == NULL) return(-1); ip->i_un.i_addr[i] = bp->b_blkno; } else bp = bread(d, nb); bap = bp->b_un.b_addr; /* * "huge" fetch of double indirect block */ if(i == 7) { i = ((bn>>7)&0177) - 7; /***/ if((nb=bap[i]) == 0) { if((nbp = alloc(d)) == NULL) { brelse(bp); return(-1); } bap[i] = nbp->b_blkno; bdwrite(bp); } else { brelse(bp); nbp = bread(d, nb); } bp = nbp; bap = bp->b_un.b_addr; } /* * normal indirect fetch */ i = bn & 0177; /***/ if((nb=bap[i]) == 0 && (nbp = alloc(d)) != NULL) { nb = nbp->b_blkno; bap[i] = nb; bdwrite(nbp); bdwrite(bp); } else brelse(bp); rablock = 0; if(i < 127) /***/ rablock = bap[i+1]; return(nb); } #else V6 daddr_t bmap(ip, bn, rwflg) register struct inode *ip; daddr_t bn; { register i; struct buf *bp, *nbp; int j, sh; daddr_t nb, *bap; dev_t dev; if(bn < 0) { u.u_error = EFBIG; return((daddr_t)0); } dev = ip->i_dev; rablock = 0; /* * blocks 0..NADDR-4 are direct blocks */ if(bn < NADDR-3) { i = bn; nb = ip->i_un.i_addr[i]; if(nb == 0) { if(rwflg==B_READ || (bp = alloc(dev))==NULL) return((daddr_t)-1); #ifdef UCB_NKB nb = dbtofsb(bp->b_blkno); #else UCB_NKB nb = bp->b_blkno; #endif UCB_NKB #ifdef UCB_NODUPS if ((ip->i_mode&IFMT) == IFDIR) /* * Write directory blocks synchronously * so they never appear with garbage in * them on the disk. */ bwrite(bp); else #endif UCB_NODUPS bdwrite(bp); ip->i_un.i_addr[i] = nb; ip->i_flag |= IUPD|ICHG; } if(i < NADDR-4) rablock = ip->i_un.i_addr[i+1]; return(nb); } /* * addresses NADDR-3, NADDR-2, and NADDR-1 * have single, double, triple indirect blocks. * the first step is to determine * how many levels of indirection. */ sh = 0; nb = 1; bn -= NADDR-3; for(j=3; j>0; j--) { sh += NSHIFT; nb <<= NSHIFT; if(bn < nb) break; bn -= nb; } if(j == 0) { u.u_error = EFBIG; return((daddr_t)0); } /* * fetch the address from the inode */ nb = ip->i_un.i_addr[NADDR-j]; if(nb == 0) { if(rwflg==B_READ || (bp = alloc(dev))==NULL) return((daddr_t)-1); #ifdef UCB_NKB nb = dbtofsb(bp->b_blkno); #else UCB_NKB nb = bp->b_blkno; #endif UCB_NKB #ifdef UCB_NODUPS /* * Write synchronously so that indirect blocks * never point at garbage. */ bwrite(bp); #else UCB_NODUPS bdwrite(bp); #endif UCB_NODUPS ip->i_un.i_addr[NADDR-j] = nb; ip->i_flag |= IUPD|ICHG; } /* * fetch through the indirect blocks */ for(; j<=3; j++) { bp = bread(dev, nb); if(bp->b_flags & B_ERROR) { brelse(bp); return((daddr_t)0); } bap = bp->b_un.b_daddr; sh -= NSHIFT; i = (bn>>sh) & NMASK; nb = bap[i]; if(nb == 0) { if(rwflg==B_READ || (nbp = alloc(dev))==NULL) { brelse(bp); return((daddr_t)-1); } #ifdef UCB_NKB nb = dbtofsb(nbp->b_blkno); #else UCB_NKB nb = nbp->b_blkno; #endif UCB_NKB #ifdef UCB_NODUPS if (j < 3 || (ip->i_mode&IFMT) == IFDIR) /* * Write synchronously so indirect blocks * never point at garbage and blocks * in directories never contain garbage. */ bwrite(nbp); else #endif UCB_NODUPS bdwrite(nbp); bap[i] = nb; bdwrite(bp); } else brelse(bp); } /* * calculate read-ahead. */ if(i < NINDIR-1) rablock = bap[i+1]; return(nb); } #endif V6 /* * Pass back c to the user at his location u_base; * update u_base, u_count, and u_offset. Return -1 * on the last character of the user's read. * u_base is in the user address space unless u_segflg is set. */ passc(c) register c; { register id; if((id = u.u_segflg) == 1) *u.u_base = c; else if(id?suibyte(u.u_base, c):subyte(u.u_base, c) < 0) { u.u_error = EFAULT; return(-1); } u.u_count--; u.u_offset++; u.u_base++; return(u.u_count == 0? -1: 0); } /* * Pick up and return the next character from the user's * write call at location u_base; * update u_base, u_count, and u_offset. Return -1 * when u_count is exhausted. u_base is in the user's * address space unless u_segflg is set. */ cpass() { register c, id; if(u.u_count == 0) return(-1); if((id = u.u_segflg) == 1) c = *u.u_base; else if((c = id==0?fubyte(u.u_base):fuibyte(u.u_base)) < 0) { u.u_error = EFAULT; return(-1); } u.u_count--; u.u_offset++; u.u_base++; return(c&0377); } /* * Routine which sets a user error; placed in * illegal entries in the bdevsw and cdevsw tables. */ nodev() { u.u_error = ENODEV; } /* * Null routine; placed in insignificant entries * in the bdevsw and cdevsw tables. */ nulldev() { } /* * Interrupt handler for spurious interrupts */ spurint(dev, stat) { printf ("\nspurious interrupt: device=0x%x status=0x%x\n", dev, stat); }