1 /* subr_xxx.c 4.11 82/06/07 */ 2 3 /* merged into kernel: @(#)subr.c 2.2 4/8/82 */ 4 5 #include "../h/param.h" 6 #include "../h/systm.h" 7 #include "../h/conf.h" 8 #include "../h/inode.h" 9 #include "../h/dir.h" 10 #include "../h/user.h" 11 #include "../h/buf.h" 12 #include "../h/proc.h" 13 #include "../h/fs.h" 14 15 /* 16 * Bmap defines the structure of file system storage 17 * by returning the physical block number on a device given the 18 * inode and the logical block number in a file. 19 * When convenient, it also leaves the physical 20 * block number of the next block of the file in rablock 21 * for use in read-ahead. 22 */ 23 /*VARARGS3*/ 24 daddr_t 25 bmap(ip, bn, rwflg, size) 26 register struct inode *ip; 27 daddr_t bn; 28 int rwflg; 29 int size; /* supplied only when rwflg == B_WRITE */ 30 { 31 register int i; 32 int osize, nsize; 33 struct buf *bp, *nbp; 34 struct fs *fs; 35 int j, sh; 36 daddr_t nb, *bap, pref, blkpref(); 37 38 if (bn < 0) { 39 u.u_error = EFBIG; 40 return ((daddr_t)0); 41 } 42 fs = ip->i_fs; 43 rablock = 0; 44 rasize = 0; /* conservative */ 45 46 /* 47 * If the next write will extend the file into a new block, 48 * and the file is currently composed of a fragment 49 * this fragment has to be extended to be a full block. 50 */ 51 nb = lblkno(fs, ip->i_size); 52 if (rwflg == B_WRITE && nb < NDADDR && nb < bn) { 53 osize = blksize(fs, ip, nb); 54 if (osize < fs->fs_bsize && osize > 0) { 55 bp = realloccg(ip, ip->i_db[nb], 56 nb == 0 ? 0 : ip->i_db[nb - 1] + fs->fs_frag, 57 osize, fs->fs_bsize); 58 ip->i_size = (nb + 1) * fs->fs_bsize; 59 ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 60 ip->i_flag |= IUPD|ICHG; 61 bdwrite(bp); 62 } 63 } 64 /* 65 * The first NDADDR blocks are direct blocks 66 */ 67 if (bn < NDADDR) { 68 i = bn; 69 nb = ip->i_db[i]; 70 if (rwflg == B_READ) { 71 if (nb == 0) 72 return ((daddr_t)-1); 73 goto gotit; 74 } 75 if (nb == 0 || ip->i_size < (i + 1) * fs->fs_bsize) { 76 if (nb != 0) { 77 /* consider need to reallocate a frag */ 78 osize = fragroundup(fs, blkoff(fs, ip->i_size)); 79 nsize = fragroundup(fs, size); 80 if (nsize <= osize) 81 goto gotit; 82 bp = realloccg(ip, nb, i == 0 ? 83 0 : ip->i_db[i - 1] + fs->fs_frag, 84 osize, nsize); 85 } else { 86 if (ip->i_size < (i + 1) * fs->fs_bsize) 87 nsize = fragroundup(fs, size); 88 else 89 nsize = fs->fs_bsize; 90 bp = alloc(ip, i > 0 ? 91 ip->i_db[i - 1] + fs->fs_frag : 0, 92 nsize); 93 } 94 if (bp == NULL) 95 return ((daddr_t)-1); 96 nb = dbtofsb(fs, bp->b_blkno); 97 if ((ip->i_mode&IFMT) == IFDIR) 98 /* 99 * Write directory blocks synchronously 100 * so they never appear with garbage in 101 * them on the disk. 102 */ 103 bwrite(bp); 104 else 105 bdwrite(bp); 106 ip->i_db[i] = nb; 107 ip->i_flag |= IUPD|ICHG; 108 } 109 gotit: 110 if (i < NDADDR - 1) { 111 rablock = fsbtodb(fs, ip->i_db[i+1]); 112 rasize = blksize(fs, ip, i+1); 113 } 114 return (nb); 115 } 116 117 /* 118 * Determine how many levels of indirection. 119 */ 120 sh = 1; 121 bn -= NDADDR; 122 for (j = NIADDR; j>0; j--) { 123 sh *= NINDIR(fs); 124 if (bn < sh) 125 break; 126 bn -= sh; 127 } 128 if (j == 0) { 129 u.u_error = EFBIG; 130 return ((daddr_t)0); 131 } 132 133 /* 134 * fetch the first indirect block 135 */ 136 nb = ip->i_ib[NIADDR - j]; 137 if (nb == 0) { 138 if (rwflg==B_READ || 139 (bp = alloc(ip, (daddr_t)0, fs->fs_bsize)) == NULL) 140 return ((daddr_t)-1); 141 nb = dbtofsb(fs, bp->b_blkno); 142 /* 143 * Write synchronously so that indirect blocks 144 * never point at garbage. 145 */ 146 bwrite(bp); 147 ip->i_ib[NIADDR - j] = nb; 148 ip->i_flag |= IUPD|ICHG; 149 } 150 151 /* 152 * fetch through the indirect blocks 153 */ 154 for (; j <= NIADDR; j++) { 155 bp = bread(ip->i_dev, fsbtodb(fs, nb), fs->fs_bsize); 156 if (bp->b_flags & B_ERROR) { 157 brelse(bp); 158 return ((daddr_t)0); 159 } 160 bap = bp->b_un.b_daddr; 161 sh /= NINDIR(fs); 162 i = (bn / sh) % NINDIR(fs); 163 nb = bap[i]; 164 if (nb == 0) { 165 if (rwflg==B_READ) { 166 brelse(bp); 167 return ((daddr_t)-1); 168 } 169 if (i % (fs->fs_fsize / sizeof(daddr_t)) == 0 || 170 bap[i - 1] == 0) 171 pref = blkpref(ip->i_fs); 172 else 173 pref = bap[i - 1] + fs->fs_frag; 174 nbp = alloc(ip, pref, fs->fs_bsize); 175 if (nbp == NULL) { 176 brelse(bp); 177 return ((daddr_t)-1); 178 } 179 nb = dbtofsb(fs, nbp->b_blkno); 180 if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR) 181 /* 182 * Write synchronously so indirect blocks 183 * never point at garbage and blocks 184 * in directories never contain garbage. 185 */ 186 bwrite(nbp); 187 else 188 bdwrite(nbp); 189 bap[i] = nb; 190 bdwrite(bp); 191 } else 192 brelse(bp); 193 } 194 195 /* 196 * calculate read-ahead. 197 */ 198 if (i < NINDIR(fs) - 1) { 199 rablock = fsbtodb(fs, bap[i+1]); 200 rasize = fs->fs_bsize; 201 } 202 return (nb); 203 } 204 205 /* 206 * Pass back c to the user at his location u_base; 207 * update u_base, u_count, and u_offset. Return -1 208 * on the last character of the user's read. 209 * u_base is in the user address space unless u_segflg is set. 210 */ 211 passc(c) 212 register c; 213 { 214 register id; 215 216 if ((id = u.u_segflg) == 1) 217 *u.u_base = c; 218 else 219 if (id?suibyte(u.u_base, c):subyte(u.u_base, c) < 0) { 220 u.u_error = EFAULT; 221 return (-1); 222 } 223 u.u_count--; 224 u.u_offset++; 225 u.u_base++; 226 return (u.u_count == 0? -1: 0); 227 } 228 229 #include "ct.h" 230 #if NCT > 0 231 /* 232 * Pick up and return the next character from the user's 233 * write call at location u_base; 234 * update u_base, u_count, and u_offset. Return -1 235 * when u_count is exhausted. u_base is in the user's 236 * address space unless u_segflg is set. 237 */ 238 cpass() 239 { 240 register c, id; 241 242 if (u.u_count == 0) 243 return (-1); 244 if ((id = u.u_segflg) == 1) 245 c = *u.u_base; 246 else 247 if ((c = id==0?fubyte(u.u_base):fuibyte(u.u_base)) < 0) { 248 u.u_error = EFAULT; 249 return (-1); 250 } 251 u.u_count--; 252 u.u_offset++; 253 u.u_base++; 254 return (c&0377); 255 } 256 #endif 257 258 /* 259 * Routine which sets a user error; placed in 260 * illegal entries in the bdevsw and cdevsw tables. 261 */ 262 nodev() 263 { 264 265 u.u_error = ENODEV; 266 } 267 268 /* 269 * Null routine; placed in insignificant entries 270 * in the bdevsw and cdevsw tables. 271 */ 272 nulldev() 273 { 274 275 } 276 277 imin(a, b) 278 { 279 280 return (a < b ? a : b); 281 } 282 283 imax(a, b) 284 { 285 286 return (a > b ? a : b); 287 } 288 289 unsigned 290 min(a, b) 291 unsigned int a, b; 292 { 293 294 return (a < b ? a : b); 295 } 296 297 unsigned 298 max(a, b) 299 unsigned int a, b; 300 { 301 302 return (a > b ? a : b); 303 } 304 305 struct proc * 306 pfind(pid) 307 int pid; 308 { 309 register struct proc *p; 310 311 for (p = &proc[pidhash[PIDHASH(pid)]]; p != &proc[0]; p = &proc[p->p_idhash]) 312 if (p->p_pid == pid) 313 return (p); 314 return ((struct proc *)0); 315 } 316