1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)ufs_bmap.c 7.1 (Berkeley) 6/5/86 7: */ 8: 9: #include "param.h" 10: #include "systm.h" 11: #include "inode.h" 12: #include "dir.h" 13: #include "user.h" 14: #include "buf.h" 15: #include "proc.h" 16: #include "fs.h" 17: 18: /* 19: * Bmap defines the structure of file system storage 20: * by returning the physical block number on a device given the 21: * inode and the logical block number in a file. 22: * When convenient, it also leaves the physical 23: * block number of the next block of the file in rablock 24: * for use in read-ahead. 25: */ 26: /*VARARGS3*/ 27: daddr_t 28: bmap(ip, bn, rwflg, size) 29: register struct inode *ip; 30: daddr_t bn; 31: int rwflg; 32: int size; /* supplied only when rwflg == B_WRITE */ 33: { 34: register int i; 35: int osize, nsize; 36: struct buf *bp, *nbp; 37: struct fs *fs; 38: int j, sh; 39: daddr_t nb, lbn, *bap, pref, blkpref(); 40: 41: if (bn < 0) { 42: u.u_error = EFBIG; 43: return ((daddr_t)0); 44: } 45: fs = ip->i_fs; 46: rablock = 0; 47: rasize = 0; /* conservative */ 48: 49: /* 50: * If the next write will extend the file into a new block, 51: * and the file is currently composed of a fragment 52: * this fragment has to be extended to be a full block. 53: */ 54: nb = lblkno(fs, ip->i_size); 55: if (rwflg == B_WRITE && nb < NDADDR && nb < bn) { 56: osize = blksize(fs, ip, nb); 57: if (osize < fs->fs_bsize && osize > 0) { 58: bp = realloccg(ip, ip->i_db[nb], 59: blkpref(ip, nb, (int)nb, &ip->i_db[0]), 60: osize, (int)fs->fs_bsize); 61: if (bp == NULL) 62: return ((daddr_t)-1); 63: ip->i_size = (nb + 1) * fs->fs_bsize; 64: ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 65: ip->i_flag |= IUPD|ICHG; 66: bdwrite(bp); 67: } 68: } 69: /* 70: * The first NDADDR blocks are direct blocks 71: */ 72: if (bn < NDADDR) { 73: nb = ip->i_db[bn]; 74: if (rwflg == B_READ) { 75: if (nb == 0) 76: return ((daddr_t)-1); 77: goto gotit; 78: } 79: if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) { 80: if (nb != 0) { 81: /* consider need to reallocate a frag */ 82: osize = fragroundup(fs, blkoff(fs, ip->i_size)); 83: nsize = fragroundup(fs, size); 84: if (nsize <= osize) 85: goto gotit; 86: bp = realloccg(ip, nb, 87: blkpref(ip, bn, (int)bn, &ip->i_db[0]), 88: osize, nsize); 89: } else { 90: if (ip->i_size < (bn + 1) * fs->fs_bsize) 91: nsize = fragroundup(fs, size); 92: else 93: nsize = fs->fs_bsize; 94: bp = alloc(ip, 95: blkpref(ip, bn, (int)bn, &ip->i_db[0]), 96: nsize); 97: } 98: if (bp == NULL) 99: return ((daddr_t)-1); 100: nb = dbtofsb(fs, bp->b_blkno); 101: if ((ip->i_mode&IFMT) == IFDIR) 102: /* 103: * Write directory blocks synchronously 104: * so they never appear with garbage in 105: * them on the disk. 106: */ 107: bwrite(bp); 108: else 109: bdwrite(bp); 110: ip->i_db[bn] = nb; 111: ip->i_flag |= IUPD|ICHG; 112: } 113: gotit: 114: if (bn < NDADDR - 1) { 115: rablock = fsbtodb(fs, ip->i_db[bn + 1]); 116: rasize = blksize(fs, ip, bn + 1); 117: } 118: return (nb); 119: } 120: 121: /* 122: * Determine how many levels of indirection. 123: */ 124: pref = 0; 125: sh = 1; 126: lbn = bn; 127: bn -= NDADDR; 128: for (j = NIADDR; j>0; j--) { 129: sh *= NINDIR(fs); 130: if (bn < sh) 131: break; 132: bn -= sh; 133: } 134: if (j == 0) { 135: u.u_error = EFBIG; 136: return ((daddr_t)0); 137: } 138: 139: /* 140: * fetch the first indirect block 141: */ 142: nb = ip->i_ib[NIADDR - j]; 143: if (nb == 0) { 144: if (rwflg == B_READ) 145: return ((daddr_t)-1); 146: pref = blkpref(ip, lbn, 0, (daddr_t *)0); 147: bp = alloc(ip, pref, (int)fs->fs_bsize); 148: if (bp == NULL) 149: return ((daddr_t)-1); 150: nb = dbtofsb(fs, bp->b_blkno); 151: /* 152: * Write synchronously so that indirect blocks 153: * never point at garbage. 154: */ 155: bwrite(bp); 156: ip->i_ib[NIADDR - j] = nb; 157: ip->i_flag |= IUPD|ICHG; 158: } 159: 160: /* 161: * fetch through the indirect blocks 162: */ 163: for (; j <= NIADDR; j++) { 164: bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize); 165: if (bp->b_flags & B_ERROR) { 166: brelse(bp); 167: return ((daddr_t)0); 168: } 169: bap = bp->b_un.b_daddr; 170: sh /= NINDIR(fs); 171: i = (bn / sh) % NINDIR(fs); 172: nb = bap[i]; 173: if (nb == 0) { 174: if (rwflg==B_READ) { 175: brelse(bp); 176: return ((daddr_t)-1); 177: } 178: if (pref == 0) 179: if (j < NIADDR) 180: pref = blkpref(ip, lbn, 0, 181: (daddr_t *)0); 182: else 183: pref = blkpref(ip, lbn, i, &bap[0]); 184: nbp = alloc(ip, pref, (int)fs->fs_bsize); 185: if (nbp == NULL) { 186: brelse(bp); 187: return ((daddr_t)-1); 188: } 189: nb = dbtofsb(fs, nbp->b_blkno); 190: if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR) 191: /* 192: * Write synchronously so indirect blocks 193: * never point at garbage and blocks 194: * in directories never contain garbage. 195: */ 196: bwrite(nbp); 197: else 198: bdwrite(nbp); 199: bap[i] = nb; 200: bdwrite(bp); 201: } else 202: brelse(bp); 203: } 204: 205: /* 206: * calculate read-ahead. 207: */ 208: if (i < NINDIR(fs) - 1) { 209: rablock = fsbtodb(fs, bap[i+1]); 210: rasize = fs->fs_bsize; 211: } 212: return (nb); 213: }