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