1 /* lfs_balloc.c 5.3 82/11/13 */ 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 ip->i_size = (nb + 1) * fs->fs_bsize; 57 ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); 58 ip->i_flag |= IUPD|ICHG; 59 bdwrite(bp); 60 } 61 } 62 /* 63 * The first NDADDR blocks are direct blocks 64 */ 65 if (bn < NDADDR) { 66 nb = ip->i_db[bn]; 67 if (rwflg == B_READ) { 68 if (nb == 0) 69 return ((daddr_t)-1); 70 goto gotit; 71 } 72 if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) { 73 if (nb != 0) { 74 /* consider need to reallocate a frag */ 75 osize = fragroundup(fs, blkoff(fs, ip->i_size)); 76 nsize = fragroundup(fs, size); 77 if (nsize <= osize) 78 goto gotit; 79 bp = realloccg(ip, nb, 80 blkpref(ip, bn, (int)bn, &ip->i_db[0]), 81 osize, nsize); 82 } else { 83 if (ip->i_size < (bn + 1) * fs->fs_bsize) 84 nsize = fragroundup(fs, size); 85 else 86 nsize = fs->fs_bsize; 87 bp = alloc(ip, 88 blkpref(ip, bn, (int)bn, &ip->i_db[0]), 89 nsize); 90 } 91 if (bp == NULL) 92 return ((daddr_t)-1); 93 nb = dbtofsb(fs, bp->b_blkno); 94 if ((ip->i_mode&IFMT) == IFDIR) 95 /* 96 * Write directory blocks synchronously 97 * so they never appear with garbage in 98 * them on the disk. 99 */ 100 bwrite(bp); 101 else 102 bdwrite(bp); 103 ip->i_db[bn] = nb; 104 ip->i_flag |= IUPD|ICHG; 105 } 106 gotit: 107 if (bn < NDADDR - 1) { 108 rablock = fsbtodb(fs, ip->i_db[bn + 1]); 109 rasize = blksize(fs, ip, bn + 1); 110 } 111 return (nb); 112 } 113 114 /* 115 * Determine how many levels of indirection. 116 */ 117 pref = 0; 118 sh = 1; 119 lbn = bn; 120 bn -= NDADDR; 121 for (j = NIADDR; j>0; j--) { 122 sh *= NINDIR(fs); 123 if (bn < sh) 124 break; 125 bn -= sh; 126 } 127 if (j == 0) { 128 u.u_error = EFBIG; 129 return ((daddr_t)0); 130 } 131 132 /* 133 * fetch the first indirect block 134 */ 135 nb = ip->i_ib[NIADDR - j]; 136 if (nb == 0) { 137 if (rwflg == B_READ) 138 return ((daddr_t)-1); 139 pref = blkpref(ip, lbn, 0, (daddr_t *)0); 140 bp = alloc(ip, pref, (int)fs->fs_bsize); 141 if (bp == NULL) 142 return ((daddr_t)-1); 143 nb = dbtofsb(fs, bp->b_blkno); 144 /* 145 * Write synchronously so that indirect blocks 146 * never point at garbage. 147 */ 148 bwrite(bp); 149 ip->i_ib[NIADDR - j] = nb; 150 ip->i_flag |= IUPD|ICHG; 151 } 152 153 /* 154 * fetch through the indirect blocks 155 */ 156 for (; j <= NIADDR; j++) { 157 bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize); 158 if (bp->b_flags & B_ERROR) { 159 brelse(bp); 160 return ((daddr_t)0); 161 } 162 bap = bp->b_un.b_daddr; 163 sh /= NINDIR(fs); 164 i = (bn / sh) % NINDIR(fs); 165 nb = bap[i]; 166 if (nb == 0) { 167 if (rwflg==B_READ) { 168 brelse(bp); 169 return ((daddr_t)-1); 170 } 171 if (pref == 0) 172 if (j < NIADDR) 173 pref = blkpref(ip, lbn, 0, 174 (daddr_t *)0); 175 else 176 pref = blkpref(ip, lbn, i, &bap[0]); 177 nbp = alloc(ip, pref, (int)fs->fs_bsize); 178 if (nbp == NULL) { 179 brelse(bp); 180 return ((daddr_t)-1); 181 } 182 nb = dbtofsb(fs, nbp->b_blkno); 183 if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR) 184 /* 185 * Write synchronously so indirect blocks 186 * never point at garbage and blocks 187 * in directories never contain garbage. 188 */ 189 bwrite(nbp); 190 else 191 bdwrite(nbp); 192 bap[i] = nb; 193 bdwrite(bp); 194 } else 195 brelse(bp); 196 } 197 198 /* 199 * calculate read-ahead. 200 */ 201 if (i < NINDIR(fs) - 1) { 202 rablock = fsbtodb(fs, bap[i+1]); 203 rasize = fs->fs_bsize; 204 } 205 return (nb); 206 } 207