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 * @(#)ffs_balloc.c 7.2 (Berkeley) 04/02/87 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 } 214