1 /* $OpenBSD: ext2fs_balloc.c,v 1.17 2009/09/05 17:23:43 jasper Exp $ */ 2 /* $NetBSD: ext2fs_balloc.c,v 1.10 2001/07/04 21:16:01 chs Exp $ */ 3 4 /* 5 * Copyright (c) 1997 Manuel Bouyer. 6 * Copyright (c) 1982, 1986, 1989, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93 34 * Modified for ext2fs by Manuel Bouyer. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/buf.h> 40 #include <sys/proc.h> 41 #include <sys/file.h> 42 #include <sys/vnode.h> 43 44 #include <uvm/uvm_extern.h> 45 46 #include <ufs/ufs/quota.h> 47 #include <ufs/ufs/inode.h> 48 #include <ufs/ufs/ufs_extern.h> 49 50 #include <ufs/ext2fs/ext2fs.h> 51 #include <ufs/ext2fs/ext2fs_extern.h> 52 53 /* 54 * Balloc defines the structure of file system storage 55 * by allocating the physical blocks on a device given 56 * the inode and the logical block number in a file. 57 */ 58 int 59 ext2fs_buf_alloc(struct inode *ip, daddr64_t bn, int size, struct ucred *cred, 60 struct buf **bpp, int flags) 61 { 62 struct m_ext2fs *fs; 63 struct buf *bp, *nbp; 64 struct vnode *vp = ITOV(ip); 65 struct indir indirs[NIADDR + 2]; 66 int32_t nb, newb, *bap; 67 int num, i, error; 68 u_int deallocated; 69 int32_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; 70 int unwindidx = -1; 71 daddr64_t lbn, pref; 72 73 *bpp = NULL; 74 if (bn < 0) 75 return (EFBIG); 76 fs = ip->i_e2fs; 77 lbn = bn; 78 79 /* 80 * The first NDADDR blocks are direct blocks 81 */ 82 if (bn < NDADDR) { 83 nb = fs2h32(ip->i_e2fs_blocks[bn]); 84 if (nb != 0) { 85 error = bread(vp, bn, fs->e2fs_bsize, NOCRED, &bp); 86 if (error) { 87 brelse(bp); 88 return (error); 89 } 90 *bpp = bp; 91 return (0); 92 } 93 94 /* 95 * allocate a new direct block. 96 */ 97 error = ext2fs_alloc(ip, bn, 98 ext2fs_blkpref(ip, bn, (int)bn, &ip->i_e2fs_blocks[0]), 99 cred, &newb); 100 if (error) 101 return (error); 102 ip->i_e2fs_last_lblk = lbn; 103 ip->i_e2fs_last_blk = newb; 104 ip->i_e2fs_blocks[bn] = h2fs32(newb); 105 ip->i_flag |= IN_CHANGE | IN_UPDATE; 106 bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0); 107 bp->b_blkno = fsbtodb(fs, newb); 108 if (flags & B_CLRBUF) 109 clrbuf(bp); 110 *bpp = bp; 111 return (0); 112 } 113 /* 114 * Determine the number of levels of indirection. 115 */ 116 pref = 0; 117 if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0) 118 return(error); 119 #ifdef DIAGNOSTIC 120 if (num < 1) 121 panic ("ext2fs_balloc: ufs_getlbns returned indirect block"); 122 #endif 123 /* 124 * Fetch the first indirect block allocating if necessary. 125 */ 126 --num; 127 nb = fs2h32(ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]); 128 allocib = NULL; 129 allocblk = allociblk; 130 if (nb == 0) { 131 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); 132 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 133 if (error) 134 return (error); 135 nb = newb; 136 *allocblk++ = nb; 137 ip->i_e2fs_last_blk = newb; 138 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0); 139 bp->b_blkno = fsbtodb(fs, newb); 140 clrbuf(bp); 141 /* 142 * Write synchronously so that indirect blocks 143 * never point at garbage. 144 */ 145 if ((error = bwrite(bp)) != 0) 146 goto fail; 147 unwindidx = 0; 148 allocib = &ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]; 149 *allocib = h2fs32(newb); 150 ip->i_flag |= IN_CHANGE | IN_UPDATE; 151 } 152 /* 153 * Fetch through the indirect blocks, allocating as necessary. 154 */ 155 for (i = 1;;) { 156 error = bread(vp, 157 indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp); 158 if (error) { 159 brelse(bp); 160 goto fail; 161 } 162 bap = (int32_t *)bp->b_data; 163 nb = fs2h32(bap[indirs[i].in_off]); 164 if (i == num) 165 break; 166 i++; 167 if (nb != 0) { 168 brelse(bp); 169 continue; 170 } 171 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); 172 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 173 if (error) { 174 brelse(bp); 175 goto fail; 176 } 177 nb = newb; 178 *allocblk++ = nb; 179 ip->i_e2fs_last_blk = newb; 180 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0); 181 nbp->b_blkno = fsbtodb(fs, nb); 182 clrbuf(nbp); 183 /* 184 * Write synchronously so that indirect blocks 185 * never point at garbage. 186 */ 187 if ((error = bwrite(nbp)) != 0) { 188 brelse(bp); 189 goto fail; 190 } 191 if (unwindidx < 0) 192 unwindidx = i - 1; 193 bap[indirs[i - 1].in_off] = h2fs32(nb); 194 /* 195 * If required, write synchronously, otherwise use 196 * delayed write. 197 */ 198 if (flags & B_SYNC) { 199 bwrite(bp); 200 } else { 201 bdwrite(bp); 202 } 203 } 204 /* 205 * Get the data block, allocating if necessary. 206 */ 207 if (nb == 0) { 208 pref = ext2fs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]); 209 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 210 if (error) { 211 brelse(bp); 212 goto fail; 213 } 214 nb = newb; 215 *allocblk++ = nb; 216 ip->i_e2fs_last_lblk = lbn; 217 ip->i_e2fs_last_blk = newb; 218 bap[indirs[num].in_off] = h2fs32(nb); 219 /* 220 * If required, write synchronously, otherwise use 221 * delayed write. 222 */ 223 if (flags & B_SYNC) { 224 bwrite(bp); 225 } else { 226 bdwrite(bp); 227 } 228 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); 229 nbp->b_blkno = fsbtodb(fs, nb); 230 if (flags & B_CLRBUF) 231 clrbuf(nbp); 232 *bpp = nbp; 233 return (0); 234 } 235 brelse(bp); 236 if (flags & B_CLRBUF) { 237 error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp); 238 if (error) { 239 brelse(nbp); 240 goto fail; 241 } 242 } else { 243 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); 244 nbp->b_blkno = fsbtodb(fs, nb); 245 } 246 247 *bpp = nbp; 248 return (0); 249 fail: 250 /* 251 * If we have failed part way through block allocation, we 252 * have to deallocate any indirect blocks that we have allocated. 253 */ 254 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { 255 ext2fs_blkfree(ip, *blkp); 256 deallocated += fs->e2fs_bsize; 257 } 258 if (unwindidx >= 0) { 259 if (unwindidx == 0) { 260 *allocib = 0; 261 } else { 262 int r; 263 264 r = bread(vp, indirs[unwindidx].in_lbn, 265 (int)fs->e2fs_bsize, NOCRED, &bp); 266 if (r) { 267 panic("Could not unwind indirect block, error %d", r); 268 } else { 269 bap = (int32_t *)bp->b_data; 270 bap[indirs[unwindidx].in_off] = 0; 271 if (flags & B_SYNC) 272 bwrite(bp); 273 else 274 bdwrite(bp); 275 } 276 } 277 for (i = unwindidx + 1; i <= num; i++) { 278 bp = getblk(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize, 279 0, 0); 280 bp->b_flags |= B_INVAL; 281 brelse(bp); 282 } 283 } 284 if (deallocated) { 285 ip->i_e2fs_nblock -= btodb(deallocated); 286 ip->i_e2fs_flags |= IN_CHANGE | IN_UPDATE; 287 } 288 return error; 289 } 290