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